Index: head/sys/dev/ahci/ahci_pci.c =================================================================== --- head/sys/dev/ahci/ahci_pci.c (revision 275100) +++ head/sys/dev/ahci/ahci_pci.c (revision 275101) @@ -1,501 +1,509 @@ /*- * Copyright (c) 2009-2012 Alexander Motin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ahci.h" static int force_ahci = 1; TUNABLE_INT("hw.ahci.force", &force_ahci); static struct { uint32_t id; uint8_t rev; const char *name; int quirks; } ahci_ids[] = { {0x43801002, 0x00, "AMD SB600", AHCI_Q_NOMSI | AHCI_Q_ATI_PMP_BUG | AHCI_Q_MAXIO_64K}, {0x43901002, 0x00, "AMD SB7x0/SB8x0/SB9x0", AHCI_Q_ATI_PMP_BUG}, {0x43911002, 0x00, "AMD SB7x0/SB8x0/SB9x0", AHCI_Q_ATI_PMP_BUG}, {0x43921002, 0x00, "AMD SB7x0/SB8x0/SB9x0", AHCI_Q_ATI_PMP_BUG}, {0x43931002, 0x00, "AMD SB7x0/SB8x0/SB9x0", AHCI_Q_ATI_PMP_BUG}, {0x43941002, 0x00, "AMD SB7x0/SB8x0/SB9x0", AHCI_Q_ATI_PMP_BUG}, /* Not sure SB8x0/SB9x0 needs this quirk. Be conservative though */ {0x43951002, 0x00, "AMD SB8x0/SB9x0", AHCI_Q_ATI_PMP_BUG}, {0x78001022, 0x00, "AMD Hudson-2", 0}, {0x78011022, 0x00, "AMD Hudson-2", 0}, {0x78021022, 0x00, "AMD Hudson-2", 0}, {0x78031022, 0x00, "AMD Hudson-2", 0}, {0x78041022, 0x00, "AMD Hudson-2", 0}, {0x06111b21, 0x00, "ASMedia ASM2106", 0}, {0x06121b21, 0x00, "ASMedia ASM1061", 0}, {0x26528086, 0x00, "Intel ICH6", AHCI_Q_NOFORCE}, {0x26538086, 0x00, "Intel ICH6M", AHCI_Q_NOFORCE}, {0x26818086, 0x00, "Intel ESB2", 0}, {0x26828086, 0x00, "Intel ESB2", 0}, {0x26838086, 0x00, "Intel ESB2", 0}, {0x27c18086, 0x00, "Intel ICH7", 0}, {0x27c38086, 0x00, "Intel ICH7", 0}, {0x27c58086, 0x00, "Intel ICH7M", 0}, {0x27c68086, 0x00, "Intel ICH7M", 0}, {0x28218086, 0x00, "Intel ICH8", 0}, {0x28228086, 0x00, "Intel ICH8", 0}, {0x28248086, 0x00, "Intel ICH8", 0}, {0x28298086, 0x00, "Intel ICH8M", 0}, {0x282a8086, 0x00, "Intel ICH8M", 0}, {0x29228086, 0x00, "Intel ICH9", 0}, {0x29238086, 0x00, "Intel ICH9", 0}, {0x29248086, 0x00, "Intel ICH9", 0}, {0x29258086, 0x00, "Intel ICH9", 0}, {0x29278086, 0x00, "Intel ICH9", 0}, {0x29298086, 0x00, "Intel ICH9M", 0}, {0x292a8086, 0x00, "Intel ICH9M", 0}, {0x292b8086, 0x00, "Intel ICH9M", 0}, {0x292c8086, 0x00, "Intel ICH9M", 0}, {0x292f8086, 0x00, "Intel ICH9M", 0}, {0x294d8086, 0x00, "Intel ICH9", 0}, {0x294e8086, 0x00, "Intel ICH9M", 0}, {0x3a058086, 0x00, "Intel ICH10", 0}, {0x3a228086, 0x00, "Intel ICH10", 0}, {0x3a258086, 0x00, "Intel ICH10", 0}, {0x3b228086, 0x00, "Intel 5 Series/3400 Series", 0}, {0x3b238086, 0x00, "Intel 5 Series/3400 Series", 0}, {0x3b258086, 0x00, "Intel 5 Series/3400 Series", 0}, {0x3b298086, 0x00, "Intel 5 Series/3400 Series", 0}, {0x3b2c8086, 0x00, "Intel 5 Series/3400 Series", 0}, {0x3b2f8086, 0x00, "Intel 5 Series/3400 Series", 0}, {0x1c028086, 0x00, "Intel Cougar Point", 0}, {0x1c038086, 0x00, "Intel Cougar Point", 0}, {0x1c048086, 0x00, "Intel Cougar Point", 0}, {0x1c058086, 0x00, "Intel Cougar Point", 0}, {0x1d028086, 0x00, "Intel Patsburg", 0}, {0x1d048086, 0x00, "Intel Patsburg", 0}, {0x1d068086, 0x00, "Intel Patsburg", 0}, {0x28268086, 0x00, "Intel Patsburg (RAID)", 0}, {0x1e028086, 0x00, "Intel Panther Point", 0}, {0x1e038086, 0x00, "Intel Panther Point", 0}, {0x1e048086, 0x00, "Intel Panther Point (RAID)", 0}, {0x1e058086, 0x00, "Intel Panther Point (RAID)", 0}, {0x1e068086, 0x00, "Intel Panther Point (RAID)", 0}, {0x1e078086, 0x00, "Intel Panther Point (RAID)", 0}, {0x1e0e8086, 0x00, "Intel Panther Point (RAID)", 0}, {0x1e0f8086, 0x00, "Intel Panther Point (RAID)", 0}, {0x1f228086, 0x00, "Intel Avoton", 0}, {0x1f238086, 0x00, "Intel Avoton", 0}, {0x1f248086, 0x00, "Intel Avoton (RAID)", 0}, {0x1f258086, 0x00, "Intel Avoton (RAID)", 0}, {0x1f268086, 0x00, "Intel Avoton (RAID)", 0}, {0x1f278086, 0x00, "Intel Avoton (RAID)", 0}, {0x1f2e8086, 0x00, "Intel Avoton (RAID)", 0}, {0x1f2f8086, 0x00, "Intel Avoton (RAID)", 0}, {0x1f328086, 0x00, "Intel Avoton", 0}, {0x1f338086, 0x00, "Intel Avoton", 0}, {0x1f348086, 0x00, "Intel Avoton (RAID)", 0}, {0x1f358086, 0x00, "Intel Avoton (RAID)", 0}, {0x1f368086, 0x00, "Intel Avoton (RAID)", 0}, {0x1f378086, 0x00, "Intel Avoton (RAID)", 0}, {0x1f3e8086, 0x00, "Intel Avoton (RAID)", 0}, {0x1f3f8086, 0x00, "Intel Avoton (RAID)", 0}, {0x23a38086, 0x00, "Intel Coleto Creek", 0}, {0x28238086, 0x00, "Intel Wellsburg (RAID)", 0}, {0x28278086, 0x00, "Intel Wellsburg (RAID)", 0}, {0x8c028086, 0x00, "Intel Lynx Point", 0}, {0x8c038086, 0x00, "Intel Lynx Point", 0}, {0x8c048086, 0x00, "Intel Lynx Point (RAID)", 0}, {0x8c058086, 0x00, "Intel Lynx Point (RAID)", 0}, {0x8c068086, 0x00, "Intel Lynx Point (RAID)", 0}, {0x8c078086, 0x00, "Intel Lynx Point (RAID)", 0}, {0x8c0e8086, 0x00, "Intel Lynx Point (RAID)", 0}, {0x8c0f8086, 0x00, "Intel Lynx Point (RAID)", 0}, + {0x8c828086, 0x00, "Intel Wildcat Point", 0}, + {0x8c838086, 0x00, "Intel Wildcat Point", 0}, + {0x8c848086, 0x00, "Intel Wildcat Point (RAID)", 0}, + {0x8c858086, 0x00, "Intel Wildcat Point (RAID)", 0}, + {0x8c868086, 0x00, "Intel Wildcat Point (RAID)", 0}, + {0x8c878086, 0x00, "Intel Wildcat Point (RAID)", 0}, + {0x8c8e8086, 0x00, "Intel Wildcat Point (RAID)", 0}, + {0x8c8f8086, 0x00, "Intel Wildcat Point (RAID)", 0}, {0x8d028086, 0x00, "Intel Wellsburg", 0}, {0x8d048086, 0x00, "Intel Wellsburg (RAID)", 0}, {0x8d068086, 0x00, "Intel Wellsburg (RAID)", 0}, {0x8d628086, 0x00, "Intel Wellsburg", 0}, {0x8d648086, 0x00, "Intel Wellsburg (RAID)", 0}, {0x8d668086, 0x00, "Intel Wellsburg (RAID)", 0}, {0x8d6e8086, 0x00, "Intel Wellsburg (RAID)", 0}, {0x9c028086, 0x00, "Intel Lynx Point-LP", 0}, {0x9c038086, 0x00, "Intel Lynx Point-LP", 0}, {0x9c048086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, {0x9c058086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, {0x9c068086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, {0x9c078086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, {0x9c0e8086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, {0x9c0f8086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, {0x23238086, 0x00, "Intel DH89xxCC", 0}, {0x2360197b, 0x00, "JMicron JMB360", 0}, {0x2361197b, 0x00, "JMicron JMB361", AHCI_Q_NOFORCE}, {0x2362197b, 0x00, "JMicron JMB362", 0}, {0x2363197b, 0x00, "JMicron JMB363", AHCI_Q_NOFORCE}, {0x2365197b, 0x00, "JMicron JMB365", AHCI_Q_NOFORCE}, {0x2366197b, 0x00, "JMicron JMB366", AHCI_Q_NOFORCE}, {0x2368197b, 0x00, "JMicron JMB368", AHCI_Q_NOFORCE}, {0x611111ab, 0x00, "Marvell 88SE6111", AHCI_Q_NOFORCE | AHCI_Q_1CH | AHCI_Q_EDGEIS}, {0x612111ab, 0x00, "Marvell 88SE6121", AHCI_Q_NOFORCE | AHCI_Q_2CH | AHCI_Q_EDGEIS | AHCI_Q_NONCQ | AHCI_Q_NOCOUNT}, {0x614111ab, 0x00, "Marvell 88SE6141", AHCI_Q_NOFORCE | AHCI_Q_4CH | AHCI_Q_EDGEIS | AHCI_Q_NONCQ | AHCI_Q_NOCOUNT}, {0x614511ab, 0x00, "Marvell 88SE6145", AHCI_Q_NOFORCE | AHCI_Q_4CH | AHCI_Q_EDGEIS | AHCI_Q_NONCQ | AHCI_Q_NOCOUNT}, {0x91201b4b, 0x00, "Marvell 88SE912x", AHCI_Q_EDGEIS}, {0x91231b4b, 0x11, "Marvell 88SE912x", AHCI_Q_ALTSIG}, {0x91231b4b, 0x00, "Marvell 88SE912x", AHCI_Q_EDGEIS|AHCI_Q_SATA2}, {0x91251b4b, 0x00, "Marvell 88SE9125", 0}, {0x91281b4b, 0x00, "Marvell 88SE9128", AHCI_Q_ALTSIG}, {0x91301b4b, 0x00, "Marvell 88SE9130", AHCI_Q_ALTSIG}, {0x91721b4b, 0x00, "Marvell 88SE9172", 0}, {0x91821b4b, 0x00, "Marvell 88SE9182", 0}, {0x91831b4b, 0x00, "Marvell 88SS9183", 0}, {0x91a01b4b, 0x00, "Marvell 88SE91Ax", 0}, {0x92151b4b, 0x00, "Marvell 88SE9215", 0}, {0x92201b4b, 0x00, "Marvell 88SE9220", AHCI_Q_ALTSIG}, {0x92301b4b, 0x00, "Marvell 88SE9230", AHCI_Q_ALTSIG}, {0x92351b4b, 0x00, "Marvell 88SE9235", 0}, {0x06201103, 0x00, "HighPoint RocketRAID 620", 0}, {0x06201b4b, 0x00, "HighPoint RocketRAID 620", 0}, {0x06221103, 0x00, "HighPoint RocketRAID 622", 0}, {0x06221b4b, 0x00, "HighPoint RocketRAID 622", 0}, {0x06401103, 0x00, "HighPoint RocketRAID 640", 0}, {0x06401b4b, 0x00, "HighPoint RocketRAID 640", 0}, {0x06441103, 0x00, "HighPoint RocketRAID 644", 0}, {0x06441b4b, 0x00, "HighPoint RocketRAID 644", 0}, {0x06411103, 0x00, "HighPoint RocketRAID 640L", 0}, {0x06421103, 0x00, "HighPoint RocketRAID 642L", 0}, {0x06451103, 0x00, "HighPoint RocketRAID 644L", 0}, {0x044c10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, {0x044d10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, {0x044e10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, {0x044f10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, {0x045c10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, {0x045d10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, {0x045e10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, {0x045f10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, {0x055010de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, {0x055110de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, {0x055210de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, {0x055310de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, {0x055410de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, {0x055510de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, {0x055610de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, {0x055710de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, {0x055810de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, {0x055910de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, {0x055A10de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, {0x055B10de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, {0x058410de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, {0x07f010de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, {0x07f110de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, {0x07f210de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, {0x07f310de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, {0x07f410de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, {0x07f510de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, {0x07f610de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, {0x07f710de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, {0x07f810de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, {0x07f910de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, {0x07fa10de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, {0x07fb10de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, {0x0ad010de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, {0x0ad110de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, {0x0ad210de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, {0x0ad310de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, {0x0ad410de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, {0x0ad510de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, {0x0ad610de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, {0x0ad710de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, {0x0ad810de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, {0x0ad910de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, {0x0ada10de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, {0x0adb10de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, {0x0ab410de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, {0x0ab510de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, {0x0ab610de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, {0x0ab710de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, {0x0ab810de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, {0x0ab910de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, {0x0aba10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, {0x0abb10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, {0x0abc10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, {0x0abd10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, {0x0abe10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, {0x0abf10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, {0x0d8410de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, {0x0d8510de, 0x00, "NVIDIA MCP89", AHCI_Q_NOFORCE|AHCI_Q_NOAA}, {0x0d8610de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, {0x0d8710de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, {0x0d8810de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, {0x0d8910de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, {0x0d8a10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, {0x0d8b10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, {0x0d8c10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, {0x0d8d10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, {0x0d8e10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, {0x0d8f10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, {0x3781105a, 0x00, "Promise TX8660", 0}, {0x33491106, 0x00, "VIA VT8251", AHCI_Q_NOPMP|AHCI_Q_NONCQ}, {0x62871106, 0x00, "VIA VT8251", AHCI_Q_NOPMP|AHCI_Q_NONCQ}, {0x11841039, 0x00, "SiS 966", 0}, {0x11851039, 0x00, "SiS 968", 0}, {0x01861039, 0x00, "SiS 968", 0}, {0x00000000, 0x00, NULL, 0} }; static int ahci_pci_ctlr_reset(device_t dev) { if (pci_read_config(dev, PCIR_DEVVENDOR, 4) == 0x28298086 && (pci_read_config(dev, 0x92, 1) & 0xfe) == 0x04) pci_write_config(dev, 0x92, 0x01, 1); return ahci_ctlr_reset(dev); } static int ahci_probe(device_t dev) { char buf[64]; int i, valid = 0; uint32_t devid = pci_get_devid(dev); uint8_t revid = pci_get_revid(dev); /* * Ensure it is not a PCI bridge (some vendors use * the same PID and VID in PCI bridge and AHCI cards). */ if (pci_get_class(dev) == PCIC_BRIDGE) return (ENXIO); /* Is this a possible AHCI candidate? */ if (pci_get_class(dev) == PCIC_STORAGE && pci_get_subclass(dev) == PCIS_STORAGE_SATA && pci_get_progif(dev) == PCIP_STORAGE_SATA_AHCI_1_0) valid = 1; /* Is this a known AHCI chip? */ for (i = 0; ahci_ids[i].id != 0; i++) { if (ahci_ids[i].id == devid && ahci_ids[i].rev <= revid && (valid || (force_ahci == 1 && !(ahci_ids[i].quirks & AHCI_Q_NOFORCE)))) { /* Do not attach JMicrons with single PCI function. */ if (pci_get_vendor(dev) == 0x197b && (pci_read_config(dev, 0xdf, 1) & 0x40) == 0) return (ENXIO); snprintf(buf, sizeof(buf), "%s AHCI SATA controller", ahci_ids[i].name); device_set_desc_copy(dev, buf); return (BUS_PROBE_VENDOR); } } if (!valid) return (ENXIO); device_set_desc_copy(dev, "AHCI SATA controller"); return (BUS_PROBE_VENDOR); } static int ahci_ata_probe(device_t dev) { char buf[64]; int i; uint32_t devid = pci_get_devid(dev); uint8_t revid = pci_get_revid(dev); if ((intptr_t)device_get_ivars(dev) >= 0) return (ENXIO); /* Is this a known AHCI chip? */ for (i = 0; ahci_ids[i].id != 0; i++) { if (ahci_ids[i].id == devid && ahci_ids[i].rev <= revid) { snprintf(buf, sizeof(buf), "%s AHCI SATA controller", ahci_ids[i].name); device_set_desc_copy(dev, buf); return (BUS_PROBE_VENDOR); } } device_set_desc_copy(dev, "AHCI SATA controller"); return (BUS_PROBE_VENDOR); } static int ahci_pci_attach(device_t dev) { struct ahci_controller *ctlr = device_get_softc(dev); int error, i; uint32_t devid = pci_get_devid(dev); uint8_t revid = pci_get_revid(dev); i = 0; while (ahci_ids[i].id != 0 && (ahci_ids[i].id != devid || ahci_ids[i].rev > revid)) i++; ctlr->quirks = ahci_ids[i].quirks; /* Limit speed for my onboard JMicron external port. * It is not eSATA really, limit to SATA 1 */ if (pci_get_devid(dev) == 0x2363197b && pci_get_subvendor(dev) == 0x1043 && pci_get_subdevice(dev) == 0x81e4) ctlr->quirks |= AHCI_Q_SATA1_UNIT0; /* if we have a memory BAR(5) we are likely on an AHCI part */ ctlr->vendorid = pci_get_vendor(dev); ctlr->deviceid = pci_get_device(dev); ctlr->subvendorid = pci_get_subvendor(dev); ctlr->subdeviceid = pci_get_subdevice(dev); ctlr->r_rid = PCIR_BAR(5); if (!(ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &ctlr->r_rid, RF_ACTIVE))) return ENXIO; pci_enable_busmaster(dev); /* Reset controller */ if ((error = ahci_pci_ctlr_reset(dev)) != 0) { bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem); return (error); }; /* Setup interrupts. */ /* Setup MSI register parameters */ ctlr->msi = 2; /* Process hints. */ if (ctlr->quirks & AHCI_Q_NOMSI) ctlr->msi = 0; resource_int_value(device_get_name(dev), device_get_unit(dev), "msi", &ctlr->msi); ctlr->numirqs = 1; if (ctlr->msi < 0) ctlr->msi = 0; else if (ctlr->msi == 1) ctlr->msi = min(1, pci_msi_count(dev)); else if (ctlr->msi > 1) { ctlr->msi = 2; ctlr->numirqs = pci_msi_count(dev); } /* Allocate MSI if needed/present. */ if (ctlr->msi && pci_alloc_msi(dev, &ctlr->numirqs) != 0) { ctlr->msi = 0; ctlr->numirqs = 1; } error = ahci_attach(dev); if (error != 0) if (ctlr->msi) pci_release_msi(dev); return error; } static int ahci_pci_detach(device_t dev) { ahci_detach(dev); pci_release_msi(dev); return (0); } static int ahci_pci_suspend(device_t dev) { struct ahci_controller *ctlr = device_get_softc(dev); bus_generic_suspend(dev); /* Disable interupts, so the state change(s) doesn't trigger */ ATA_OUTL(ctlr->r_mem, AHCI_GHC, ATA_INL(ctlr->r_mem, AHCI_GHC) & (~AHCI_GHC_IE)); return 0; } static int ahci_pci_resume(device_t dev) { int res; if ((res = ahci_pci_ctlr_reset(dev)) != 0) return (res); ahci_ctlr_setup(dev); return (bus_generic_resume(dev)); } devclass_t ahci_devclass; static device_method_t ahci_methods[] = { DEVMETHOD(device_probe, ahci_probe), DEVMETHOD(device_attach, ahci_pci_attach), DEVMETHOD(device_detach, ahci_pci_detach), DEVMETHOD(device_suspend, ahci_pci_suspend), DEVMETHOD(device_resume, ahci_pci_resume), DEVMETHOD(bus_print_child, ahci_print_child), DEVMETHOD(bus_alloc_resource, ahci_alloc_resource), DEVMETHOD(bus_release_resource, ahci_release_resource), DEVMETHOD(bus_setup_intr, ahci_setup_intr), DEVMETHOD(bus_teardown_intr,ahci_teardown_intr), DEVMETHOD(bus_child_location_str, ahci_child_location_str), DEVMETHOD(bus_get_dma_tag, ahci_get_dma_tag), { 0, 0 } }; static driver_t ahci_driver = { "ahci", ahci_methods, sizeof(struct ahci_controller) }; DRIVER_MODULE(ahci, pci, ahci_driver, ahci_devclass, 0, 0); static device_method_t ahci_ata_methods[] = { DEVMETHOD(device_probe, ahci_ata_probe), DEVMETHOD(device_attach, ahci_pci_attach), DEVMETHOD(device_detach, ahci_pci_detach), DEVMETHOD(device_suspend, ahci_pci_suspend), DEVMETHOD(device_resume, ahci_pci_resume), DEVMETHOD(bus_print_child, ahci_print_child), DEVMETHOD(bus_alloc_resource, ahci_alloc_resource), DEVMETHOD(bus_release_resource, ahci_release_resource), DEVMETHOD(bus_setup_intr, ahci_setup_intr), DEVMETHOD(bus_teardown_intr,ahci_teardown_intr), DEVMETHOD(bus_child_location_str, ahci_child_location_str), { 0, 0 } }; static driver_t ahci_ata_driver = { "ahci", ahci_ata_methods, sizeof(struct ahci_controller) }; DRIVER_MODULE(ahci, atapci, ahci_ata_driver, ahci_devclass, 0, 0); Index: head/sys/dev/ata/ata-pci.h =================================================================== --- head/sys/dev/ata/ata-pci.h (revision 275100) +++ head/sys/dev/ata/ata-pci.h (revision 275101) @@ -1,661 +1,674 @@ /*- * Copyright (c) 2003 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ /* structure holding chipset config info */ struct ata_chip_id { u_int32_t chipid; u_int8_t chiprev; int cfg1; int cfg2; u_int8_t max_dma; const char *text; }; #define ATA_PCI_MAX_CH 8 /* structure describing a PCI ATA controller */ struct ata_pci_controller { device_t dev; int r_type1; int r_rid1; struct resource *r_res1; int r_type2; int r_rid2; struct resource *r_res2; int r_irq_rid; struct resource *r_irq; void *handle; const struct ata_chip_id *chip; int legacy; int channels; int ichannels; int (*chipinit)(device_t); int (*chipdeinit)(device_t); int (*suspend)(device_t); int (*resume)(device_t); int (*ch_attach)(device_t); int (*ch_detach)(device_t); int (*ch_suspend)(device_t); int (*ch_resume)(device_t); void (*reset)(device_t); int (*setmode)(device_t, int, int); int (*getrev)(device_t, int); struct { void (*function)(void *); void *argument; } interrupt[ATA_PCI_MAX_CH]; void *chipset_data; }; /* defines for known chipset PCI id's */ #define ATA_ACARD_ID 0x1191 #define ATA_ATP850 0x00021191 #define ATA_ATP850A 0x00041191 #define ATA_ATP850R 0x00051191 #define ATA_ATP860A 0x00061191 #define ATA_ATP860R 0x00071191 #define ATA_ATP865A 0x00081191 #define ATA_ATP865R 0x00091191 #define ATA_ACER_LABS_ID 0x10b9 #define ATA_ALI_1533 0x153310b9 #define ATA_ALI_5228 0x522810b9 #define ATA_ALI_5229 0x522910b9 #define ATA_ALI_5281 0x528110b9 #define ATA_ALI_5287 0x528710b9 #define ATA_ALI_5288 0x528810b9 #define ATA_ALI_5289 0x528910b9 #define ATA_AMD_ID 0x1022 #define ATA_AMD755 0x74011022 #define ATA_AMD756 0x74091022 #define ATA_AMD766 0x74111022 #define ATA_AMD768 0x74411022 #define ATA_AMD8111 0x74691022 #define ATA_AMD5536 0x209a1022 #define ATA_AMD_HUDSON2_S1 0x78001022 #define ATA_AMD_HUDSON2_S2 0x78011022 #define ATA_AMD_HUDSON2_S3 0x78021022 #define ATA_AMD_HUDSON2_S4 0x78031022 #define ATA_AMD_HUDSON2_S5 0x78041022 #define ATA_AMD_HUDSON2 0x780c1022 #define ATA_ADAPTEC_ID 0x9005 #define ATA_ADAPTEC_1420 0x02419005 #define ATA_ADAPTEC_1430 0x02439005 #define ATA_ATI_ID 0x1002 #define ATA_ATI_IXP200 0x43491002 #define ATA_ATI_IXP300 0x43691002 #define ATA_ATI_IXP300_S1 0x436e1002 #define ATA_ATI_IXP400 0x43761002 #define ATA_ATI_IXP400_S1 0x43791002 #define ATA_ATI_IXP400_S2 0x437a1002 #define ATA_ATI_IXP600 0x438c1002 #define ATA_ATI_IXP600_S1 0x43801002 #define ATA_ATI_IXP700 0x439c1002 #define ATA_ATI_IXP700_S1 0x43901002 #define ATA_ATI_IXP700_S2 0x43911002 #define ATA_ATI_IXP700_S3 0x43921002 #define ATA_ATI_IXP700_S4 0x43931002 #define ATA_ATI_IXP800_S1 0x43941002 #define ATA_ATI_IXP800_S2 0x43951002 #define ATA_CENATEK_ID 0x16ca #define ATA_CENATEK_ROCKET 0x000116ca #define ATA_CYRIX_ID 0x1078 #define ATA_CYRIX_5530 0x01021078 #define ATA_CYPRESS_ID 0x1080 #define ATA_CYPRESS_82C693 0xc6931080 #define ATA_DEC_21150 0x00221011 #define ATA_DEC_21150_1 0x00231011 #define ATA_HIGHPOINT_ID 0x1103 #define ATA_HPT366 0x00041103 #define ATA_HPT372 0x00051103 #define ATA_HPT302 0x00061103 #define ATA_HPT371 0x00071103 #define ATA_HPT374 0x00081103 #define ATA_INTEL_ID 0x8086 #define ATA_I960RM 0x09628086 #define ATA_I82371FB 0x12308086 #define ATA_I82371SB 0x70108086 #define ATA_I82371AB 0x71118086 #define ATA_I82443MX 0x71998086 #define ATA_I82451NX 0x84ca8086 #define ATA_I82372FB 0x76018086 #define ATA_I82801AB 0x24218086 #define ATA_I82801AA 0x24118086 #define ATA_I82801BA 0x244a8086 #define ATA_I82801BA_1 0x244b8086 #define ATA_I82801CA 0x248a8086 #define ATA_I82801CA_1 0x248b8086 #define ATA_I82801DB 0x24cb8086 #define ATA_I82801DB_1 0x24ca8086 #define ATA_I82801EB 0x24db8086 #define ATA_I82801EB_S1 0x24d18086 #define ATA_I82801EB_R1 0x24df8086 #define ATA_I6300ESB 0x25a28086 #define ATA_I6300ESB_S1 0x25a38086 #define ATA_I6300ESB_R1 0x25b08086 #define ATA_I63XXESB2 0x269e8086 #define ATA_I63XXESB2_S1 0x26808086 #define ATA_I63XXESB2_S2 0x26818086 #define ATA_I63XXESB2_R1 0x26828086 #define ATA_I63XXESB2_R2 0x26838086 #define ATA_I82801FB 0x266f8086 #define ATA_I82801FB_S1 0x26518086 #define ATA_I82801FB_R1 0x26528086 #define ATA_I82801FBM 0x26538086 #define ATA_I82801GB 0x27df8086 #define ATA_I82801GB_S1 0x27c08086 #define ATA_I82801GB_AH 0x27c18086 #define ATA_I82801GB_R1 0x27c38086 #define ATA_I82801GBM_S1 0x27c48086 #define ATA_I82801GBM_AH 0x27c58086 #define ATA_I82801GBM_R1 0x27c68086 #define ATA_I82801HB_S1 0x28208086 #define ATA_I82801HB_AH6 0x28218086 #define ATA_I82801HB_R1 0x28228086 #define ATA_I82801HB_AH4 0x28248086 #define ATA_I82801HB_S2 0x28258086 #define ATA_I82801HBM 0x28508086 #define ATA_I82801HBM_S1 0x28288086 #define ATA_I82801HBM_S2 0x28298086 #define ATA_I82801HBM_S3 0x282a8086 #define ATA_I82801IB_S1 0x29208086 #define ATA_I82801IB_S3 0x29218086 #define ATA_I82801IB_AH6 0x29228086 #define ATA_I82801IB_AH4 0x29238086 #define ATA_I82801IB_R1 0x29258086 #define ATA_I82801IB_S2 0x29268086 #define ATA_I82801IBM_S1 0x29288086 #define ATA_I82801IBM_AH 0x29298086 #define ATA_I82801IBM_R1 0x292a8086 #define ATA_I82801IBM_S2 0x292d8086 #define ATA_I82801JIB_S1 0x3a208086 #define ATA_I82801JIB_AH 0x3a228086 #define ATA_I82801JIB_R1 0x3a258086 #define ATA_I82801JIB_S2 0x3a268086 #define ATA_I82801JD_S1 0x3a008086 #define ATA_I82801JD_AH 0x3a028086 #define ATA_I82801JD_R1 0x3a058086 #define ATA_I82801JD_S2 0x3a068086 #define ATA_I82801JI_S1 0x3a208086 #define ATA_I82801JI_AH 0x3a228086 #define ATA_I82801JI_R1 0x3a258086 #define ATA_I82801JI_S2 0x3a268086 #define ATA_5Series_S1 0x3b208086 #define ATA_5Series_S2 0x3b218086 #define ATA_5Series_AH1 0x3b228086 #define ATA_5Series_AH2 0x3b238086 #define ATA_5Series_R1 0x3b258086 #define ATA_5Series_S3 0x3b268086 #define ATA_5Series_S4 0x3b288086 #define ATA_5Series_AH3 0x3b298086 #define ATA_5Series_R2 0x3b2c8086 #define ATA_5Series_S5 0x3b2d8086 #define ATA_5Series_S6 0x3b2e8086 #define ATA_5Series_AH4 0x3b2f8086 #define ATA_CPT_S1 0x1c008086 #define ATA_CPT_S2 0x1c018086 #define ATA_CPT_AH1 0x1c028086 #define ATA_CPT_AH2 0x1c038086 #define ATA_CPT_R1 0x1c048086 #define ATA_CPT_R2 0x1c058086 #define ATA_CPT_S3 0x1c088086 #define ATA_CPT_S4 0x1c098086 #define ATA_PBG_S1 0x1d008086 #define ATA_PBG_AH1 0x1d028086 #define ATA_PBG_R1 0x1d048086 #define ATA_PBG_R2 0x1d068086 #define ATA_PBG_R3 0x28268086 #define ATA_PBG_S2 0x1d088086 #define ATA_PPT_S1 0x1e008086 #define ATA_PPT_S2 0x1e018086 #define ATA_PPT_AH1 0x1e028086 #define ATA_PPT_AH2 0x1e038086 #define ATA_PPT_R1 0x1e048086 #define ATA_PPT_R2 0x1e058086 #define ATA_PPT_R3 0x1e068086 #define ATA_PPT_R4 0x1e078086 #define ATA_PPT_S3 0x1e088086 #define ATA_PPT_S4 0x1e098086 #define ATA_PPT_R5 0x1e0e8086 #define ATA_PPT_R6 0x1e0f8086 #define ATA_AVOTON_S1 0x1f208086 #define ATA_AVOTON_S2 0x1f218086 #define ATA_AVOTON_S3 0x1f308086 #define ATA_AVOTON_S4 0x1f318086 #define ATA_LPT_S1 0x8c008086 #define ATA_LPT_S2 0x8c018086 #define ATA_LPT_AH1 0x8c028086 #define ATA_LPT_AH2 0x8c038086 #define ATA_LPT_R1 0x8c048086 #define ATA_LPT_R2 0x8c058086 #define ATA_LPT_R3 0x8c068086 #define ATA_LPT_R4 0x8c078086 #define ATA_LPT_S3 0x8c088086 #define ATA_LPT_S4 0x8c098086 #define ATA_LPT_R5 0x8c0e8086 #define ATA_LPT_R6 0x8c0f8086 +#define ATA_WCPT_S1 0x8c808086 +#define ATA_WCPT_S2 0x8c818086 +#define ATA_WCPT_AH1 0x8c828086 +#define ATA_WCPT_AH2 0x8c838086 +#define ATA_WCPT_R1 0x8c848086 +#define ATA_WCPT_R2 0x8c858086 +#define ATA_WCPT_R3 0x8c868086 +#define ATA_WCPT_R4 0x8c878086 +#define ATA_WCPT_S3 0x8c888086 +#define ATA_WCPT_S4 0x8c898086 +#define ATA_WCPT_R5 0x8c8e8086 +#define ATA_WCPT_R6 0x8c8f8086 + #define ATA_WELLS_S1 0x8d008086 #define ATA_WELLS_S2 0x8d088086 #define ATA_WELLS_S3 0x8d608086 #define ATA_WELLS_S4 0x8d688086 #define ATA_LPTLP_S1 0x9c008086 #define ATA_LPTLP_S2 0x9c018086 #define ATA_LPTLP_S3 0x9c088086 #define ATA_LPTLP_S4 0x9c098086 #define ATA_I31244 0x32008086 #define ATA_ISCH 0x811a8086 #define ATA_DH89XXCC 0x23238086 #define ATA_COLETOCRK_AH1 0x23a38086 #define ATA_COLETOCRK_S1 0x23a18086 #define ATA_COLETOCRK_S2 0x23a68086 #define ATA_ITE_ID 0x1283 #define ATA_IT8211F 0x82111283 #define ATA_IT8212F 0x82121283 #define ATA_IT8213F 0x82131283 #define ATA_JMICRON_ID 0x197b #define ATA_JMB360 0x2360197b #define ATA_JMB361 0x2361197b #define ATA_JMB362 0x2362197b #define ATA_JMB363 0x2363197b #define ATA_JMB365 0x2365197b #define ATA_JMB366 0x2366197b #define ATA_JMB368 0x2368197b #define ATA_JMB368_2 0x0368197b #define ATA_MARVELL_ID 0x11ab #define ATA_M88SX5040 0x504011ab #define ATA_M88SX5041 0x504111ab #define ATA_M88SX5080 0x508011ab #define ATA_M88SX5081 0x508111ab #define ATA_M88SX6041 0x604111ab #define ATA_M88SX6042 0x604211ab #define ATA_M88SX6081 0x608111ab #define ATA_M88SX7042 0x704211ab #define ATA_M88SE6101 0x610111ab #define ATA_M88SE6102 0x610211ab #define ATA_M88SE6111 0x611111ab #define ATA_M88SE6121 0x612111ab #define ATA_M88SE6141 0x614111ab #define ATA_M88SE6145 0x614511ab #define ATA_MARVELL2_ID 0x1b4b #define ATA_MICRON_ID 0x1042 #define ATA_MICRON_RZ1000 0x10001042 #define ATA_MICRON_RZ1001 0x10011042 #define ATA_NATIONAL_ID 0x100b #define ATA_SC1100 0x0502100b #define ATA_NETCELL_ID 0x169c #define ATA_NETCELL_SR 0x0044169c #define ATA_NVIDIA_ID 0x10de #define ATA_NFORCE1 0x01bc10de #define ATA_NFORCE2 0x006510de #define ATA_NFORCE2_PRO 0x008510de #define ATA_NFORCE2_PRO_S1 0x008e10de #define ATA_NFORCE3 0x00d510de #define ATA_NFORCE3_PRO 0x00e510de #define ATA_NFORCE3_PRO_S1 0x00e310de #define ATA_NFORCE3_PRO_S2 0x00ee10de #define ATA_NFORCE_MCP04 0x003510de #define ATA_NFORCE_MCP04_S1 0x003610de #define ATA_NFORCE_MCP04_S2 0x003e10de #define ATA_NFORCE_CK804 0x005310de #define ATA_NFORCE_CK804_S1 0x005410de #define ATA_NFORCE_CK804_S2 0x005510de #define ATA_NFORCE_MCP51 0x026510de #define ATA_NFORCE_MCP51_S1 0x026610de #define ATA_NFORCE_MCP51_S2 0x026710de #define ATA_NFORCE_MCP55 0x036e10de #define ATA_NFORCE_MCP55_S1 0x037e10de #define ATA_NFORCE_MCP55_S2 0x037f10de #define ATA_NFORCE_MCP61 0x03ec10de #define ATA_NFORCE_MCP61_S1 0x03e710de #define ATA_NFORCE_MCP61_S2 0x03f610de #define ATA_NFORCE_MCP61_S3 0x03f710de #define ATA_NFORCE_MCP65 0x044810de #define ATA_NFORCE_MCP65_A0 0x044c10de #define ATA_NFORCE_MCP65_A1 0x044d10de #define ATA_NFORCE_MCP65_A2 0x044e10de #define ATA_NFORCE_MCP65_A3 0x044f10de #define ATA_NFORCE_MCP65_A4 0x045c10de #define ATA_NFORCE_MCP65_A5 0x045d10de #define ATA_NFORCE_MCP65_A6 0x045e10de #define ATA_NFORCE_MCP65_A7 0x045f10de #define ATA_NFORCE_MCP67 0x056010de #define ATA_NFORCE_MCP67_A0 0x055010de #define ATA_NFORCE_MCP67_A1 0x055110de #define ATA_NFORCE_MCP67_A2 0x055210de #define ATA_NFORCE_MCP67_A3 0x055310de #define ATA_NFORCE_MCP67_A4 0x055410de #define ATA_NFORCE_MCP67_A5 0x055510de #define ATA_NFORCE_MCP67_A6 0x055610de #define ATA_NFORCE_MCP67_A7 0x055710de #define ATA_NFORCE_MCP67_A8 0x055810de #define ATA_NFORCE_MCP67_A9 0x055910de #define ATA_NFORCE_MCP67_AA 0x055A10de #define ATA_NFORCE_MCP67_AB 0x055B10de #define ATA_NFORCE_MCP67_AC 0x058410de #define ATA_NFORCE_MCP73 0x056c10de #define ATA_NFORCE_MCP73_A0 0x07f010de #define ATA_NFORCE_MCP73_A1 0x07f110de #define ATA_NFORCE_MCP73_A2 0x07f210de #define ATA_NFORCE_MCP73_A3 0x07f310de #define ATA_NFORCE_MCP73_A4 0x07f410de #define ATA_NFORCE_MCP73_A5 0x07f510de #define ATA_NFORCE_MCP73_A6 0x07f610de #define ATA_NFORCE_MCP73_A7 0x07f710de #define ATA_NFORCE_MCP73_A8 0x07f810de #define ATA_NFORCE_MCP73_A9 0x07f910de #define ATA_NFORCE_MCP73_AA 0x07fa10de #define ATA_NFORCE_MCP73_AB 0x07fb10de #define ATA_NFORCE_MCP77 0x075910de #define ATA_NFORCE_MCP77_A0 0x0ad010de #define ATA_NFORCE_MCP77_A1 0x0ad110de #define ATA_NFORCE_MCP77_A2 0x0ad210de #define ATA_NFORCE_MCP77_A3 0x0ad310de #define ATA_NFORCE_MCP77_A4 0x0ad410de #define ATA_NFORCE_MCP77_A5 0x0ad510de #define ATA_NFORCE_MCP77_A6 0x0ad610de #define ATA_NFORCE_MCP77_A7 0x0ad710de #define ATA_NFORCE_MCP77_A8 0x0ad810de #define ATA_NFORCE_MCP77_A9 0x0ad910de #define ATA_NFORCE_MCP77_AA 0x0ada10de #define ATA_NFORCE_MCP77_AB 0x0adb10de #define ATA_NFORCE_MCP79_A0 0x0ab410de #define ATA_NFORCE_MCP79_A1 0x0ab510de #define ATA_NFORCE_MCP79_A2 0x0ab610de #define ATA_NFORCE_MCP79_A3 0x0ab710de #define ATA_NFORCE_MCP79_A4 0x0ab810de #define ATA_NFORCE_MCP79_A5 0x0ab910de #define ATA_NFORCE_MCP79_A6 0x0aba10de #define ATA_NFORCE_MCP79_A7 0x0abb10de #define ATA_NFORCE_MCP79_A8 0x0abc10de #define ATA_NFORCE_MCP79_A9 0x0abd10de #define ATA_NFORCE_MCP79_AA 0x0abe10de #define ATA_NFORCE_MCP79_AB 0x0abf10de #define ATA_NFORCE_MCP89_A0 0x0d8410de #define ATA_NFORCE_MCP89_A1 0x0d8510de #define ATA_NFORCE_MCP89_A2 0x0d8610de #define ATA_NFORCE_MCP89_A3 0x0d8710de #define ATA_NFORCE_MCP89_A4 0x0d8810de #define ATA_NFORCE_MCP89_A5 0x0d8910de #define ATA_NFORCE_MCP89_A6 0x0d8a10de #define ATA_NFORCE_MCP89_A7 0x0d8b10de #define ATA_NFORCE_MCP89_A8 0x0d8c10de #define ATA_NFORCE_MCP89_A9 0x0d8d10de #define ATA_NFORCE_MCP89_AA 0x0d8e10de #define ATA_NFORCE_MCP89_AB 0x0d8f10de #define ATA_PROMISE_ID 0x105a #define ATA_PDC20246 0x4d33105a #define ATA_PDC20262 0x4d38105a #define ATA_PDC20263 0x0d38105a #define ATA_PDC20265 0x0d30105a #define ATA_PDC20267 0x4d30105a #define ATA_PDC20268 0x4d68105a #define ATA_PDC20269 0x4d69105a #define ATA_PDC20270 0x6268105a #define ATA_PDC20271 0x6269105a #define ATA_PDC20275 0x1275105a #define ATA_PDC20276 0x5275105a #define ATA_PDC20277 0x7275105a #define ATA_PDC20318 0x3318105a #define ATA_PDC20319 0x3319105a #define ATA_PDC20371 0x3371105a #define ATA_PDC20375 0x3375105a #define ATA_PDC20376 0x3376105a #define ATA_PDC20377 0x3377105a #define ATA_PDC20378 0x3373105a #define ATA_PDC20379 0x3372105a #define ATA_PDC20571 0x3571105a #define ATA_PDC20575 0x3d75105a #define ATA_PDC20579 0x3574105a #define ATA_PDC20771 0x3570105a #define ATA_PDC40518 0x3d18105a #define ATA_PDC40519 0x3519105a #define ATA_PDC40718 0x3d17105a #define ATA_PDC40719 0x3515105a #define ATA_PDC40775 0x3d73105a #define ATA_PDC40779 0x3577105a #define ATA_PDC20617 0x6617105a #define ATA_PDC20618 0x6626105a #define ATA_PDC20619 0x6629105a #define ATA_PDC20620 0x6620105a #define ATA_PDC20621 0x6621105a #define ATA_PDC20622 0x6622105a #define ATA_PDC20624 0x6624105a #define ATA_PDC81518 0x8002105a #define ATA_SERVERWORKS_ID 0x1166 #define ATA_ROSB4_ISA 0x02001166 #define ATA_ROSB4 0x02111166 #define ATA_CSB5 0x02121166 #define ATA_CSB6 0x02131166 #define ATA_CSB6_1 0x02171166 #define ATA_HT1000 0x02141166 #define ATA_HT1000_S1 0x024b1166 #define ATA_HT1000_S2 0x024a1166 #define ATA_K2 0x02401166 #define ATA_FRODO4 0x02411166 #define ATA_FRODO8 0x02421166 #define ATA_SILICON_IMAGE_ID 0x1095 #define ATA_SII3114 0x31141095 #define ATA_SII3512 0x35121095 #define ATA_SII3112 0x31121095 #define ATA_SII3112_1 0x02401095 #define ATA_SII3124 0x31241095 #define ATA_SII3132 0x31321095 #define ATA_SII3132_1 0x02421095 #define ATA_SII3132_2 0x02441095 #define ATA_SII0680 0x06801095 #define ATA_CMD646 0x06461095 #define ATA_CMD648 0x06481095 #define ATA_CMD649 0x06491095 #define ATA_SIS_ID 0x1039 #define ATA_SISSOUTH 0x00081039 #define ATA_SIS5511 0x55111039 #define ATA_SIS5513 0x55131039 #define ATA_SIS5517 0x55171039 #define ATA_SIS5518 0x55181039 #define ATA_SIS5571 0x55711039 #define ATA_SIS5591 0x55911039 #define ATA_SIS5596 0x55961039 #define ATA_SIS5597 0x55971039 #define ATA_SIS5598 0x55981039 #define ATA_SIS5600 0x56001039 #define ATA_SIS530 0x05301039 #define ATA_SIS540 0x05401039 #define ATA_SIS550 0x05501039 #define ATA_SIS620 0x06201039 #define ATA_SIS630 0x06301039 #define ATA_SIS635 0x06351039 #define ATA_SIS633 0x06331039 #define ATA_SIS640 0x06401039 #define ATA_SIS645 0x06451039 #define ATA_SIS646 0x06461039 #define ATA_SIS648 0x06481039 #define ATA_SIS650 0x06501039 #define ATA_SIS651 0x06511039 #define ATA_SIS652 0x06521039 #define ATA_SIS655 0x06551039 #define ATA_SIS658 0x06581039 #define ATA_SIS661 0x06611039 #define ATA_SIS730 0x07301039 #define ATA_SIS733 0x07331039 #define ATA_SIS735 0x07351039 #define ATA_SIS740 0x07401039 #define ATA_SIS745 0x07451039 #define ATA_SIS746 0x07461039 #define ATA_SIS748 0x07481039 #define ATA_SIS750 0x07501039 #define ATA_SIS751 0x07511039 #define ATA_SIS752 0x07521039 #define ATA_SIS755 0x07551039 #define ATA_SIS961 0x09611039 #define ATA_SIS962 0x09621039 #define ATA_SIS963 0x09631039 #define ATA_SIS964 0x09641039 #define ATA_SIS965 0x09651039 #define ATA_SIS180 0x01801039 #define ATA_SIS181 0x01811039 #define ATA_SIS182 0x01821039 #define ATA_VIA_ID 0x1106 #define ATA_VIA82C571 0x05711106 #define ATA_VIA82C586 0x05861106 #define ATA_VIA82C596 0x05961106 #define ATA_VIA82C686 0x06861106 #define ATA_VIA8231 0x82311106 #define ATA_VIA8233 0x30741106 #define ATA_VIA8233A 0x31471106 #define ATA_VIA8233C 0x31091106 #define ATA_VIA8235 0x31771106 #define ATA_VIA8237 0x32271106 #define ATA_VIA8237A 0x05911106 #define ATA_VIA8237S 0x53371106 #define ATA_VIA8237_5372 0x53721106 #define ATA_VIA8237_7372 0x73721106 #define ATA_VIA8251 0x33491106 #define ATA_VIA8361 0x31121106 #define ATA_VIA8363 0x03051106 #define ATA_VIA8371 0x03911106 #define ATA_VIA8662 0x31021106 #define ATA_VIA6410 0x31641106 #define ATA_VIA6420 0x31491106 #define ATA_VIA6421 0x32491106 #define ATA_VIACX700IDE 0x05811106 #define ATA_VIACX700 0x83241106 #define ATA_VIASATAIDE 0x53241106 #define ATA_VIAVX800 0x83531106 #define ATA_VIASATAIDE2 0xc4091106 #define ATA_VIAVX855 0x84091106 #define ATA_VIASATAIDE3 0x90011106 #define ATA_VIAVX900 0x84101106 /* global prototypes ata-pci.c */ int ata_pci_probe(device_t dev); int ata_pci_attach(device_t dev); int ata_pci_detach(device_t dev); int ata_pci_suspend(device_t dev); int ata_pci_resume(device_t dev); int ata_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result); int ata_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value); uint32_t ata_pci_read_config(device_t dev, device_t child, int reg, int width); void ata_pci_write_config(device_t dev, device_t child, int reg, uint32_t val, int width); int ata_pci_print_child(device_t dev, device_t child); int ata_pci_child_location_str(device_t dev, device_t child, char *buf, size_t buflen); struct resource * ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags); int ata_pci_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r); int ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_filter_t *filter, driver_intr_t *function, void *argument, void **cookiep); int ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie); int ata_pci_ch_attach(device_t dev); int ata_pci_ch_detach(device_t dev); int ata_pci_status(device_t dev); void ata_pci_hw(device_t dev); void ata_pci_dmainit(device_t dev); void ata_pci_dmafini(device_t dev); const char *ata_pcivendor2str(device_t dev); int ata_legacy(device_t); void ata_generic_intr(void *data); int ata_generic_chipinit(device_t dev); int ata_generic_setmode(device_t dev, int target, int mode); int ata_setup_interrupt(device_t dev, void *intr_func); void ata_set_desc(device_t dev); const struct ata_chip_id *ata_match_chip(device_t dev, const struct ata_chip_id *index); const struct ata_chip_id *ata_find_chip(device_t dev, const struct ata_chip_id *index, int slot); int ata_mode2idx(int mode); /* global prototypes from chipsets/ata-*.c */ int ata_ahci_chipinit(device_t); int ata_marvell_edma_chipinit(device_t); int ata_sii_chipinit(device_t); /* externs */ extern devclass_t ata_pci_devclass; MALLOC_DECLARE(M_ATAPCI); /* macro for easy definition of all driver module stuff */ #define ATA_DECLARE_DRIVER(dname) \ static device_method_t __CONCAT(dname,_methods)[] = { \ DEVMETHOD(device_probe, __CONCAT(dname,_probe)), \ DEVMETHOD(device_attach, ata_pci_attach), \ DEVMETHOD(device_detach, ata_pci_detach), \ DEVMETHOD(device_suspend, ata_pci_suspend), \ DEVMETHOD(device_resume, ata_pci_resume), \ DEVMETHOD(device_shutdown, bus_generic_shutdown), \ DEVMETHOD(bus_read_ivar, ata_pci_read_ivar), \ DEVMETHOD(bus_write_ivar, ata_pci_write_ivar), \ DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource), \ DEVMETHOD(bus_release_resource, ata_pci_release_resource), \ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), \ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), \ DEVMETHOD(bus_setup_intr, ata_pci_setup_intr), \ DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr), \ DEVMETHOD(pci_read_config, ata_pci_read_config), \ DEVMETHOD(pci_write_config, ata_pci_write_config), \ DEVMETHOD(bus_print_child, ata_pci_print_child), \ DEVMETHOD(bus_child_location_str, ata_pci_child_location_str), \ DEVMETHOD_END \ }; \ static driver_t __CONCAT(dname,_driver) = { \ "atapci", \ __CONCAT(dname,_methods), \ sizeof(struct ata_pci_controller) \ }; \ DRIVER_MODULE(dname, pci, __CONCAT(dname,_driver), ata_pci_devclass, NULL, NULL); \ MODULE_VERSION(dname, 1); \ MODULE_DEPEND(dname, ata, 1, 1, 1); \ MODULE_DEPEND(dname, atapci, 1, 1, 1); Index: head/sys/dev/ata/chipsets/ata-intel.c =================================================================== --- head/sys/dev/ata/chipsets/ata-intel.c (revision 275100) +++ head/sys/dev/ata/chipsets/ata-intel.c (revision 275101) @@ -1,986 +1,998 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* local prototypes */ static int ata_intel_chipinit(device_t dev); static int ata_intel_chipdeinit(device_t dev); static int ata_intel_ch_attach(device_t dev); static void ata_intel_reset(device_t dev); static int ata_intel_old_setmode(device_t dev, int target, int mode); static int ata_intel_new_setmode(device_t dev, int target, int mode); static int ata_intel_sch_setmode(device_t dev, int target, int mode); static int ata_intel_sata_getrev(device_t dev, int target); static int ata_intel_sata_status(device_t dev); static int ata_intel_sata_ahci_read(device_t dev, int port, int reg, u_int32_t *result); static int ata_intel_sata_cscr_read(device_t dev, int port, int reg, u_int32_t *result); static int ata_intel_sata_sidpr_read(device_t dev, int port, int reg, u_int32_t *result); static int ata_intel_sata_ahci_write(device_t dev, int port, int reg, u_int32_t result); static int ata_intel_sata_cscr_write(device_t dev, int port, int reg, u_int32_t result); static int ata_intel_sata_sidpr_write(device_t dev, int port, int reg, u_int32_t result); static int ata_intel_sata_sidpr_test(device_t dev); static int ata_intel_31244_ch_attach(device_t dev); static int ata_intel_31244_ch_detach(device_t dev); static int ata_intel_31244_status(device_t dev); static void ata_intel_31244_tf_write(struct ata_request *request); static void ata_intel_31244_reset(device_t dev); /* misc defines */ #define INTEL_AHCI 1 #define INTEL_ICH5 2 #define INTEL_6CH 4 #define INTEL_6CH2 8 #define INTEL_ICH7 16 struct ata_intel_data { struct mtx lock; u_char smap[4]; }; #define ATA_INTEL_SMAP(ctlr, ch) \ &((struct ata_intel_data *)((ctlr)->chipset_data))->smap[(ch)->unit * 2] #define ATA_INTEL_LOCK(ctlr) \ mtx_lock(&((struct ata_intel_data *)((ctlr)->chipset_data))->lock) #define ATA_INTEL_UNLOCK(ctlr) \ mtx_unlock(&((struct ata_intel_data *)((ctlr)->chipset_data))->lock) /* * Intel chipset support functions */ static int ata_intel_probe(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); static const struct ata_chip_id ids[] = {{ ATA_I82371FB, 0, 0, 2, ATA_WDMA2, "PIIX" }, { ATA_I82371SB, 0, 0, 2, ATA_WDMA2, "PIIX3" }, { ATA_I82371AB, 0, 0, 2, ATA_UDMA2, "PIIX4" }, { ATA_I82443MX, 0, 0, 2, ATA_UDMA2, "PIIX4" }, { ATA_I82451NX, 0, 0, 2, ATA_UDMA2, "PIIX4" }, { ATA_I82801AB, 0, 0, 2, ATA_UDMA2, "ICH0" }, { ATA_I82801AA, 0, 0, 2, ATA_UDMA4, "ICH" }, { ATA_I82372FB, 0, 0, 2, ATA_UDMA4, "ICH" }, { ATA_I82801BA, 0, 0, 2, ATA_UDMA5, "ICH2" }, { ATA_I82801BA_1, 0, 0, 2, ATA_UDMA5, "ICH2" }, { ATA_I82801CA, 0, 0, 2, ATA_UDMA5, "ICH3" }, { ATA_I82801CA_1, 0, 0, 2, ATA_UDMA5, "ICH3" }, { ATA_I82801DB, 0, 0, 2, ATA_UDMA5, "ICH4" }, { ATA_I82801DB_1, 0, 0, 2, ATA_UDMA5, "ICH4" }, { ATA_I82801EB, 0, 0, 2, ATA_UDMA5, "ICH5" }, { ATA_I82801EB_S1, 0, INTEL_ICH5, 2, ATA_SA150, "ICH5" }, { ATA_I82801EB_R1, 0, INTEL_ICH5, 2, ATA_SA150, "ICH5" }, { ATA_I6300ESB, 0, 0, 2, ATA_UDMA5, "6300ESB" }, { ATA_I6300ESB_S1, 0, INTEL_ICH5, 2, ATA_SA150, "6300ESB" }, { ATA_I6300ESB_R1, 0, INTEL_ICH5, 2, ATA_SA150, "6300ESB" }, { ATA_I82801FB, 0, 0, 2, ATA_UDMA5, "ICH6" }, { ATA_I82801FB_S1, 0, INTEL_AHCI, 0, ATA_SA150, "ICH6" }, { ATA_I82801FB_R1, 0, INTEL_AHCI, 0, ATA_SA150, "ICH6" }, { ATA_I82801FBM, 0, INTEL_AHCI, 0, ATA_SA150, "ICH6M" }, { ATA_I82801GB, 0, 0, 1, ATA_UDMA5, "ICH7" }, { ATA_I82801GB_S1, 0, INTEL_ICH7, 0, ATA_SA300, "ICH7" }, { ATA_I82801GB_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH7" }, { ATA_I82801GB_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH7" }, { ATA_I82801GBM_S1, 0, INTEL_ICH7, 0, ATA_SA150, "ICH7M" }, { ATA_I82801GBM_R1, 0, INTEL_AHCI, 0, ATA_SA150, "ICH7M" }, { ATA_I82801GBM_AH, 0, INTEL_AHCI, 0, ATA_SA150, "ICH7M" }, { ATA_I63XXESB2, 0, 0, 1, ATA_UDMA5, "63XXESB2" }, { ATA_I63XXESB2_S1, 0, 0, 0, ATA_SA300, "63XXESB2" }, { ATA_I63XXESB2_S2, 0, INTEL_AHCI, 0, ATA_SA300, "63XXESB2" }, { ATA_I63XXESB2_R1, 0, INTEL_AHCI, 0, ATA_SA300, "63XXESB2" }, { ATA_I63XXESB2_R2, 0, INTEL_AHCI, 0, ATA_SA300, "63XXESB2" }, { ATA_I82801HB_S1, 0, INTEL_6CH, 0, ATA_SA300, "ICH8" }, { ATA_I82801HB_S2, 0, INTEL_6CH2, 0, ATA_SA300, "ICH8" }, { ATA_I82801HB_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" }, { ATA_I82801HB_AH4, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" }, { ATA_I82801HB_AH6, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" }, { ATA_I82801HBM, 0, 0, 1, ATA_UDMA5, "ICH8M" }, { ATA_I82801HBM_S1, 0, INTEL_6CH, 0, ATA_SA300, "ICH8M" }, { ATA_I82801HBM_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8M" }, { ATA_I82801HBM_S3, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8M" }, { ATA_I82801IB_S1, 0, INTEL_6CH, 0, ATA_SA300, "ICH9" }, { ATA_I82801IB_S2, 0, INTEL_6CH2, 0, ATA_SA300, "ICH9" }, { ATA_I82801IB_S3, 0, INTEL_6CH2, 0, ATA_SA300, "ICH9" }, { ATA_I82801IB_AH4, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" }, { ATA_I82801IB_AH6, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" }, { ATA_I82801IB_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" }, { ATA_I82801IBM_S1, 0, INTEL_6CH2, 0, ATA_SA300, "ICH9M" }, { ATA_I82801IBM_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9M" }, { ATA_I82801IBM_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9M" }, { ATA_I82801IBM_S2, 0, INTEL_6CH2, 0, ATA_SA300, "ICH9M" }, { ATA_I82801JIB_S1, 0, INTEL_6CH, 0, ATA_SA300, "ICH10" }, { ATA_I82801JIB_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, { ATA_I82801JIB_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, { ATA_I82801JIB_S2, 0, INTEL_6CH2, 0, ATA_SA300, "ICH10" }, { ATA_I82801JD_S1, 0, INTEL_6CH, 0, ATA_SA300, "ICH10" }, { ATA_I82801JD_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, { ATA_I82801JD_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, { ATA_I82801JD_S2, 0, INTEL_6CH2, 0, ATA_SA300, "ICH10" }, { ATA_I82801JI_S1, 0, INTEL_6CH, 0, ATA_SA300, "ICH10" }, { ATA_I82801JI_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, { ATA_I82801JI_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, { ATA_I82801JI_S2, 0, INTEL_6CH2, 0, ATA_SA300, "ICH10" }, { ATA_5Series_S1, 0, INTEL_6CH, 0, ATA_SA300, "5 Series/3400 Series PCH" }, { ATA_5Series_S2, 0, INTEL_6CH2, 0, ATA_SA300, "5 Series/3400 Series PCH" }, { ATA_5Series_AH1, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" }, { ATA_5Series_AH2, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" }, { ATA_5Series_R1, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" }, { ATA_5Series_S3, 0, INTEL_6CH2, 0, ATA_SA300, "5 Series/3400 Series PCH" }, { ATA_5Series_S4, 0, INTEL_6CH, 0, ATA_SA300, "5 Series/3400 Series PCH" }, { ATA_5Series_AH3, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" }, { ATA_5Series_R2, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" }, { ATA_5Series_S5, 0, INTEL_6CH2, 0, ATA_SA300, "5 Series/3400 Series PCH" }, { ATA_5Series_S6, 0, INTEL_6CH, 0, ATA_SA300, "5 Series/3400 Series PCH" }, { ATA_5Series_AH4, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" }, { ATA_CPT_S1, 0, INTEL_6CH, 0, ATA_SA300, "Cougar Point" }, { ATA_CPT_S2, 0, INTEL_6CH, 0, ATA_SA300, "Cougar Point" }, { ATA_CPT_AH1, 0, INTEL_AHCI, 0, ATA_SA300, "Cougar Point" }, { ATA_CPT_AH2, 0, INTEL_AHCI, 0, ATA_SA300, "Cougar Point" }, { ATA_CPT_R1, 0, INTEL_AHCI, 0, ATA_SA300, "Cougar Point" }, { ATA_CPT_R2, 0, INTEL_AHCI, 0, ATA_SA300, "Cougar Point" }, { ATA_CPT_S3, 0, INTEL_6CH2, 0, ATA_SA300, "Cougar Point" }, { ATA_CPT_S4, 0, INTEL_6CH2, 0, ATA_SA300, "Cougar Point" }, { ATA_PBG_S1, 0, INTEL_6CH, 0, ATA_SA300, "Patsburg" }, { ATA_PBG_AH1, 0, INTEL_AHCI, 0, ATA_SA300, "Patsburg" }, { ATA_PBG_R1, 0, INTEL_AHCI, 0, ATA_SA300, "Patsburg" }, { ATA_PBG_R2, 0, INTEL_AHCI, 0, ATA_SA300, "Patsburg" }, { ATA_PBG_R3, 0, INTEL_AHCI, 0, ATA_SA300, "Patsburg" }, { ATA_PBG_S2, 0, INTEL_6CH2, 0, ATA_SA300, "Patsburg" }, { ATA_PPT_S1, 0, INTEL_6CH, 0, ATA_SA300, "Panther Point" }, { ATA_PPT_S2, 0, INTEL_6CH, 0, ATA_SA300, "Panther Point" }, { ATA_PPT_AH1, 0, INTEL_AHCI, 0, ATA_SA300, "Panther Point" }, { ATA_PPT_AH2, 0, INTEL_AHCI, 0, ATA_SA300, "Panther Point" }, { ATA_PPT_R1, 0, INTEL_AHCI, 0, ATA_SA300, "Panther Point" }, { ATA_PPT_R2, 0, INTEL_AHCI, 0, ATA_SA300, "Panther Point" }, { ATA_PPT_R3, 0, INTEL_AHCI, 0, ATA_SA300, "Panther Point" }, { ATA_PPT_R4, 0, INTEL_AHCI, 0, ATA_SA300, "Panther Point" }, { ATA_PPT_S3, 0, INTEL_6CH2, 0, ATA_SA300, "Panther Point" }, { ATA_PPT_S4, 0, INTEL_6CH2, 0, ATA_SA300, "Panther Point" }, { ATA_PPT_R5, 0, INTEL_AHCI, 0, ATA_SA300, "Panther Point" }, { ATA_PPT_R6, 0, INTEL_AHCI, 0, ATA_SA300, "Panther Point" }, { ATA_AVOTON_S1, 0, INTEL_6CH, 0, ATA_SA300, "Avoton" }, { ATA_AVOTON_S2, 0, INTEL_6CH, 0, ATA_SA300, "Avoton" }, { ATA_AVOTON_S3, 0, INTEL_6CH2, 0, ATA_SA300, "Avoton" }, { ATA_AVOTON_S4, 0, INTEL_6CH2, 0, ATA_SA300, "Avoton" }, { ATA_LPT_S1, 0, INTEL_6CH, 0, ATA_SA300, "Lynx Point" }, { ATA_LPT_S2, 0, INTEL_6CH, 0, ATA_SA300, "Lynx Point" }, { ATA_LPT_AH1, 0, INTEL_AHCI, 0, ATA_SA300, "Lynx Point" }, { ATA_LPT_AH2, 0, INTEL_AHCI, 0, ATA_SA300, "Lynx Point" }, { ATA_LPT_R1, 0, INTEL_AHCI, 0, ATA_SA300, "Lynx Point" }, { ATA_LPT_R2, 0, INTEL_AHCI, 0, ATA_SA300, "Lynx Point" }, { ATA_LPT_R3, 0, INTEL_AHCI, 0, ATA_SA300, "Lynx Point" }, { ATA_LPT_R4, 0, INTEL_AHCI, 0, ATA_SA300, "Lynx Point" }, { ATA_LPT_S3, 0, INTEL_6CH2, 0, ATA_SA300, "Lynx Point" }, { ATA_LPT_S4, 0, INTEL_6CH2, 0, ATA_SA300, "Lynx Point" }, { ATA_LPT_R5, 0, INTEL_AHCI, 0, ATA_SA300, "Lynx Point" }, { ATA_LPT_R6, 0, INTEL_AHCI, 0, ATA_SA300, "Lynx Point" }, + { ATA_WCPT_S1, 0, INTEL_6CH, 0, ATA_SA300, "Wildcat Point" }, + { ATA_WCPT_S2, 0, INTEL_6CH, 0, ATA_SA300, "Wildcat Point" }, + { ATA_WCPT_AH1, 0, INTEL_AHCI, 0, ATA_SA300, "Wildcat Point" }, + { ATA_WCPT_AH2, 0, INTEL_AHCI, 0, ATA_SA300, "Wildcat Point" }, + { ATA_WCPT_R1, 0, INTEL_AHCI, 0, ATA_SA300, "Wildcat Point" }, + { ATA_WCPT_R2, 0, INTEL_AHCI, 0, ATA_SA300, "Wildcat Point" }, + { ATA_WCPT_R3, 0, INTEL_AHCI, 0, ATA_SA300, "Wildcat Point" }, + { ATA_WCPT_R4, 0, INTEL_AHCI, 0, ATA_SA300, "Wildcat Point" }, + { ATA_WCPT_S3, 0, INTEL_6CH2, 0, ATA_SA300, "Wildcat Point" }, + { ATA_WCPT_S4, 0, INTEL_6CH2, 0, ATA_SA300, "Wildcat Point" }, + { ATA_WCPT_R5, 0, INTEL_AHCI, 0, ATA_SA300, "Wildcat Point" }, + { ATA_WCPT_R6, 0, INTEL_AHCI, 0, ATA_SA300, "Wildcat Point" }, { ATA_WELLS_S1, 0, INTEL_6CH, 0, ATA_SA300, "Wellsburg" }, { ATA_WELLS_S2, 0, INTEL_6CH2, 0, ATA_SA300, "Wellsburg" }, { ATA_WELLS_S3, 0, INTEL_6CH, 0, ATA_SA300, "Wellsburg" }, { ATA_WELLS_S4, 0, INTEL_6CH2, 0, ATA_SA300, "Wellsburg" }, { ATA_LPTLP_S1, 0, INTEL_6CH, 0, ATA_SA300, "Lynx Point-LP" }, { ATA_LPTLP_S2, 0, INTEL_6CH, 0, ATA_SA300, "Lynx Point-LP" }, { ATA_LPTLP_S3, 0, INTEL_6CH2, 0, ATA_SA300, "Lynx Point-LP" }, { ATA_LPTLP_S4, 0, INTEL_6CH2, 0, ATA_SA300, "Lynx Point-LP" }, { ATA_I31244, 0, 0, 2, ATA_SA150, "31244" }, { ATA_ISCH, 0, 0, 1, ATA_UDMA5, "SCH" }, { ATA_DH89XXCC, 0, INTEL_AHCI, 0, ATA_SA300, "DH89xxCC" }, { ATA_COLETOCRK_S1, 0, INTEL_6CH2, 0, ATA_SA300, "COLETOCRK" }, { ATA_COLETOCRK_S2, 0, INTEL_6CH2, 0, ATA_SA300, "COLETOCRK" }, { ATA_COLETOCRK_AH1,0, INTEL_AHCI, 0, ATA_SA300, "COLETOCRK" }, { 0, 0, 0, 0, 0, 0}}; if (pci_get_vendor(dev) != ATA_INTEL_ID) return ENXIO; if (!(ctlr->chip = ata_match_chip(dev, ids))) return ENXIO; ata_set_desc(dev); ctlr->chipinit = ata_intel_chipinit; ctlr->chipdeinit = ata_intel_chipdeinit; return (BUS_PROBE_DEFAULT); } static int ata_intel_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); struct ata_intel_data *data; if (ata_setup_interrupt(dev, ata_generic_intr)) return ENXIO; data = malloc(sizeof(struct ata_intel_data), M_ATAPCI, M_WAITOK | M_ZERO); mtx_init(&data->lock, "Intel SATA lock", NULL, MTX_DEF); ctlr->chipset_data = (void *)data; /* good old PIIX needs special treatment (not implemented) */ if (ctlr->chip->chipid == ATA_I82371FB) { ctlr->setmode = ata_intel_old_setmode; } /* the intel 31244 needs special care if in DPA mode */ else if (ctlr->chip->chipid == ATA_I31244) { if (pci_get_subclass(dev) != PCIS_STORAGE_IDE) { ctlr->r_type2 = SYS_RES_MEMORY; ctlr->r_rid2 = PCIR_BAR(0); if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, &ctlr->r_rid2, RF_ACTIVE))) return ENXIO; ctlr->channels = 4; ctlr->ch_attach = ata_intel_31244_ch_attach; ctlr->ch_detach = ata_intel_31244_ch_detach; ctlr->reset = ata_intel_31244_reset; } ctlr->setmode = ata_sata_setmode; ctlr->getrev = ata_sata_getrev; } /* SCH */ else if (ctlr->chip->chipid == ATA_ISCH) { ctlr->channels = 1; ctlr->ch_attach = ata_intel_ch_attach; ctlr->ch_detach = ata_pci_ch_detach; ctlr->setmode = ata_intel_sch_setmode; } /* non SATA intel chips goes here */ else if (ctlr->chip->max_dma < ATA_SA150) { ctlr->channels = ctlr->chip->cfg2; ctlr->ch_attach = ata_intel_ch_attach; ctlr->ch_detach = ata_pci_ch_detach; ctlr->setmode = ata_intel_new_setmode; } /* SATA parts can be either compat or AHCI */ else { /* force all ports active "the legacy way" */ pci_write_config(dev, 0x92, pci_read_config(dev, 0x92, 2) | 0x0f, 2); ctlr->ch_attach = ata_intel_ch_attach; ctlr->ch_detach = ata_pci_ch_detach; ctlr->reset = ata_intel_reset; /* * if we have AHCI capability and AHCI or RAID mode enabled * in BIOS we try for AHCI mode */ if ((ctlr->chip->cfg1 & INTEL_AHCI) && (pci_read_config(dev, 0x90, 1) & 0xc0) && (ata_ahci_chipinit(dev) != ENXIO)) return 0; /* BAR(5) may point to SATA interface registers */ if ((ctlr->chip->cfg1 & INTEL_ICH7)) { ctlr->r_type2 = SYS_RES_MEMORY; ctlr->r_rid2 = PCIR_BAR(5); ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, &ctlr->r_rid2, RF_ACTIVE); if (ctlr->r_res2 != NULL) { /* Set SCRAE bit to enable registers access. */ pci_write_config(dev, 0x94, pci_read_config(dev, 0x94, 4) | (1 << 9), 4); /* Set Ports Implemented register bits. */ ATA_OUTL(ctlr->r_res2, 0x0C, ATA_INL(ctlr->r_res2, 0x0C) | 0xf); } /* Skip BAR(5) on ICH8M Apples, system locks up on access. */ } else if (ctlr->chip->chipid != ATA_I82801HBM_S1 || pci_get_subvendor(dev) != 0x106b) { ctlr->r_type2 = SYS_RES_IOPORT; ctlr->r_rid2 = PCIR_BAR(5); ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, &ctlr->r_rid2, RF_ACTIVE); } if (ctlr->r_res2 != NULL || (ctlr->chip->cfg1 & INTEL_ICH5)) ctlr->getrev = ata_intel_sata_getrev; ctlr->setmode = ata_sata_setmode; } return 0; } static int ata_intel_chipdeinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); struct ata_intel_data *data; data = ctlr->chipset_data; mtx_destroy(&data->lock); free(data, M_ATAPCI); ctlr->chipset_data = NULL; return (0); } static int ata_intel_ch_attach(device_t dev) { struct ata_pci_controller *ctlr; struct ata_channel *ch; u_char *smap; u_int map; /* setup the usual register normal pci style */ if (ata_pci_ch_attach(dev)) return (ENXIO); ctlr = device_get_softc(device_get_parent(dev)); ch = device_get_softc(dev); /* if r_res2 is valid it points to SATA interface registers */ if (ctlr->r_res2) { ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2; ch->r_io[ATA_IDX_ADDR].offset = 0x00; ch->r_io[ATA_IDX_DATA].res = ctlr->r_res2; ch->r_io[ATA_IDX_DATA].offset = 0x04; } ch->flags |= ATA_ALWAYS_DMASTAT; if (ctlr->chip->max_dma >= ATA_SA150) { smap = ATA_INTEL_SMAP(ctlr, ch); map = pci_read_config(device_get_parent(dev), 0x90, 1); if (ctlr->chip->cfg1 & INTEL_ICH5) { map &= 0x07; if ((map & 0x04) == 0) { ch->flags |= ATA_SATA; ch->flags |= ATA_NO_SLAVE; smap[0] = (map & 0x01) ^ ch->unit; smap[1] = 0; } else if ((map & 0x02) == 0 && ch->unit == 0) { ch->flags |= ATA_SATA; smap[0] = (map & 0x01) ? 1 : 0; smap[1] = (map & 0x01) ? 0 : 1; } else if ((map & 0x02) != 0 && ch->unit == 1) { ch->flags |= ATA_SATA; smap[0] = (map & 0x01) ? 1 : 0; smap[1] = (map & 0x01) ? 0 : 1; } } else if (ctlr->chip->cfg1 & INTEL_6CH2) { ch->flags |= ATA_SATA; ch->flags |= ATA_NO_SLAVE; smap[0] = (ch->unit == 0) ? 0 : 1; smap[1] = 0; } else { map &= 0x03; if (map == 0x00) { ch->flags |= ATA_SATA; smap[0] = (ch->unit == 0) ? 0 : 1; smap[1] = (ch->unit == 0) ? 2 : 3; } else if (map == 0x02 && ch->unit == 0) { ch->flags |= ATA_SATA; smap[0] = 0; smap[1] = 2; } else if (map == 0x01 && ch->unit == 1) { ch->flags |= ATA_SATA; smap[0] = 1; smap[1] = 3; } } if (ch->flags & ATA_SATA) { if ((ctlr->chip->cfg1 & INTEL_ICH5)) { ch->hw.pm_read = ata_intel_sata_cscr_read; ch->hw.pm_write = ata_intel_sata_cscr_write; } else if (ctlr->r_res2) { if ((ctlr->chip->cfg1 & INTEL_ICH7)) { ch->hw.pm_read = ata_intel_sata_ahci_read; ch->hw.pm_write = ata_intel_sata_ahci_write; } else if (ata_intel_sata_sidpr_test(dev)) { ch->hw.pm_read = ata_intel_sata_sidpr_read; ch->hw.pm_write = ata_intel_sata_sidpr_write; }; } if (ch->hw.pm_write != NULL) { ch->flags |= ATA_PERIODIC_POLL; ch->hw.status = ata_intel_sata_status; ata_sata_scr_write(ch, 0, ATA_SERROR, 0xffffffff); if ((ch->flags & ATA_NO_SLAVE) == 0) { ata_sata_scr_write(ch, 1, ATA_SERROR, 0xffffffff); } } } else ctlr->setmode = ata_intel_new_setmode; } else if (ctlr->chip->chipid != ATA_ISCH) ch->flags |= ATA_CHECKS_CABLE; return (0); } static void ata_intel_reset(device_t dev) { device_t parent = device_get_parent(dev); struct ata_pci_controller *ctlr = device_get_softc(parent); struct ata_channel *ch = device_get_softc(dev); int mask, pshift, timeout, devs; u_char *smap; uint16_t pcs; /* In combined mode, skip SATA stuff for PATA channel. */ if ((ch->flags & ATA_SATA) == 0) return (ata_generic_reset(dev)); /* Do hard-reset on respective SATA ports. */ smap = ATA_INTEL_SMAP(ctlr, ch); mask = 1 << smap[0]; if ((ch->flags & ATA_NO_SLAVE) == 0) mask |= (1 << smap[1]); pci_write_config(parent, 0x92, pci_read_config(parent, 0x92, 2) & ~mask, 2); DELAY(10); pci_write_config(parent, 0x92, pci_read_config(parent, 0x92, 2) | mask, 2); /* Wait up to 1 sec for "connect well". */ if (ctlr->chip->cfg1 & (INTEL_6CH | INTEL_6CH2)) pshift = 8; else pshift = 4; for (timeout = 0; timeout < 100 ; timeout++) { pcs = (pci_read_config(parent, 0x92, 2) >> pshift) & mask; if ((pcs == mask) && (ATA_IDX_INB(ch, ATA_STATUS) != 0xff)) break; ata_udelay(10000); } if (bootverbose) device_printf(dev, "SATA reset: ports status=0x%02x\n", pcs); /* If any device found, do soft-reset. */ if (ch->hw.pm_read != NULL) { devs = ata_sata_phy_reset(dev, 0, 2) ? ATA_ATA_MASTER : 0; if ((ch->flags & ATA_NO_SLAVE) == 0) devs |= ata_sata_phy_reset(dev, 1, 2) ? ATA_ATA_SLAVE : 0; } else { devs = (pcs & (1 << smap[0])) ? ATA_ATA_MASTER : 0; if ((ch->flags & ATA_NO_SLAVE) == 0) devs |= (pcs & (1 << smap[1])) ? ATA_ATA_SLAVE : 0; } if (devs) { ata_generic_reset(dev); /* Reset may give fake slave when only ATAPI master present. */ ch->devices &= (devs | (devs * ATA_ATAPI_MASTER)); } else ch->devices = 0; } static int ata_intel_old_setmode(device_t dev, int target, int mode) { device_t parent = device_get_parent(dev); struct ata_pci_controller *ctlr = device_get_softc(parent); mode = min(mode, ctlr->chip->max_dma); return (mode); } static int ata_intel_new_setmode(device_t dev, int target, int mode) { device_t parent = device_get_parent(dev); struct ata_pci_controller *ctlr = device_get_softc(parent); struct ata_channel *ch = device_get_softc(dev); int devno = (ch->unit << 1) + target; int piomode; u_int32_t reg40 = pci_read_config(parent, 0x40, 4); u_int8_t reg44 = pci_read_config(parent, 0x44, 1); u_int8_t reg48 = pci_read_config(parent, 0x48, 1); u_int16_t reg4a = pci_read_config(parent, 0x4a, 2); u_int16_t reg54 = pci_read_config(parent, 0x54, 2); u_int32_t mask40 = 0, new40 = 0; u_int8_t mask44 = 0, new44 = 0; static const uint8_t timings[] = { 0x00, 0x00, 0x10, 0x21, 0x23, 0x00, 0x21, 0x23 }; static const uint8_t utimings[] = { 0x00, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02 }; /* In combined mode, skip PATA stuff for SATA channel. */ if (ch->flags & ATA_SATA) return (ata_sata_setmode(dev, target, mode)); mode = min(mode, ctlr->chip->max_dma); if (ata_dma_check_80pin && mode > ATA_UDMA2 && !(reg54 & (0x10 << devno))) { ata_print_cable(dev, "controller"); mode = ATA_UDMA2; } /* Enable/disable UDMA and set timings. */ if (mode >= ATA_UDMA0) { pci_write_config(parent, 0x48, reg48 | (0x0001 << devno), 2); pci_write_config(parent, 0x4a, (reg4a & ~(0x3 << (devno << 2))) | (utimings[mode & ATA_MODE_MASK] << (devno<<2)), 2); piomode = ATA_PIO4; } else { pci_write_config(parent, 0x48, reg48 & ~(0x0001 << devno), 2); pci_write_config(parent, 0x4a, (reg4a & ~(0x3 << (devno << 2))),2); piomode = mode; } reg54 |= 0x0400; /* Set UDMA reference clock (33/66/133MHz). */ reg54 &= ~(0x1001 << devno); if (mode >= ATA_UDMA5) reg54 |= (0x1000 << devno); else if (mode >= ATA_UDMA3) reg54 |= (0x1 << devno); pci_write_config(parent, 0x54, reg54, 2); /* Allow PIO/WDMA timing controls. */ reg40 &= ~0x00ff00ff; reg40 |= 0x40774077; /* Set PIO/WDMA timings. */ if (target == 0) { mask40 = 0x3300; new40 = timings[ata_mode2idx(piomode)] << 8; } else { mask44 = 0x0f; new44 = ((timings[ata_mode2idx(piomode)] & 0x30) >> 2) | (timings[ata_mode2idx(piomode)] & 0x03); } if (ch->unit) { mask40 <<= 16; new40 <<= 16; mask44 <<= 4; new44 <<= 4; } pci_write_config(parent, 0x40, (reg40 & ~mask40) | new40, 4); pci_write_config(parent, 0x44, (reg44 & ~mask44) | new44, 1); return (mode); } static int ata_intel_sch_setmode(device_t dev, int target, int mode) { device_t parent = device_get_parent(dev); struct ata_pci_controller *ctlr = device_get_softc(parent); u_int8_t dtim = 0x80 + (target << 2); u_int32_t tim = pci_read_config(parent, dtim, 4); int piomode; mode = min(mode, ctlr->chip->max_dma); if (mode >= ATA_UDMA0) { tim |= (0x1 << 31); tim &= ~(0x7 << 16); tim |= ((mode & ATA_MODE_MASK) << 16); piomode = ATA_PIO4; } else if (mode >= ATA_WDMA0) { tim &= ~(0x1 << 31); tim &= ~(0x3 << 8); tim |= ((mode & ATA_MODE_MASK) << 8); piomode = (mode == ATA_WDMA0) ? ATA_PIO0 : (mode == ATA_WDMA1) ? ATA_PIO3 : ATA_PIO4; } else piomode = mode; tim &= ~(0x7); tim |= (piomode & 0x7); pci_write_config(parent, dtim, tim, 4); return (mode); } static int ata_intel_sata_getrev(device_t dev, int target) { struct ata_channel *ch = device_get_softc(dev); uint32_t status; if (ata_sata_scr_read(ch, target, ATA_SSTATUS, &status) == 0) return ((status & 0x0f0) >> 4); return (0xff); } static int ata_intel_sata_status(device_t dev) { struct ata_channel *ch = device_get_softc(dev); ata_sata_phy_check_events(dev, 0); if ((ch->flags & ATA_NO_SLAVE) == 0) ata_sata_phy_check_events(dev, 1); return ata_pci_status(dev); } static int ata_intel_sata_ahci_read(device_t dev, int port, int reg, u_int32_t *result) { struct ata_pci_controller *ctlr; struct ata_channel *ch; device_t parent; u_char *smap; int offset; parent = device_get_parent(dev); ctlr = device_get_softc(parent); ch = device_get_softc(dev); port = (port == 1) ? 1 : 0; smap = ATA_INTEL_SMAP(ctlr, ch); offset = 0x100 + smap[port] * 0x80; switch (reg) { case ATA_SSTATUS: reg = 0x28; break; case ATA_SCONTROL: reg = 0x2c; break; case ATA_SERROR: reg = 0x30; break; default: return (EINVAL); } *result = ATA_INL(ctlr->r_res2, offset + reg); return (0); } static int ata_intel_sata_cscr_read(device_t dev, int port, int reg, u_int32_t *result) { struct ata_pci_controller *ctlr; struct ata_channel *ch; device_t parent; u_char *smap; parent = device_get_parent(dev); ctlr = device_get_softc(parent); ch = device_get_softc(dev); smap = ATA_INTEL_SMAP(ctlr, ch); port = (port == 1) ? 1 : 0; switch (reg) { case ATA_SSTATUS: reg = 0; break; case ATA_SERROR: reg = 1; break; case ATA_SCONTROL: reg = 2; break; default: return (EINVAL); } ATA_INTEL_LOCK(ctlr); pci_write_config(parent, 0xa0, 0x50 + smap[port] * 0x10 + reg * 4, 4); *result = pci_read_config(parent, 0xa4, 4); ATA_INTEL_UNLOCK(ctlr); return (0); } static int ata_intel_sata_sidpr_read(device_t dev, int port, int reg, u_int32_t *result) { struct ata_pci_controller *ctlr; struct ata_channel *ch; device_t parent; parent = device_get_parent(dev); ctlr = device_get_softc(parent); ch = device_get_softc(dev); port = (port == 1) ? 1 : 0; switch (reg) { case ATA_SSTATUS: reg = 0; break; case ATA_SCONTROL: reg = 1; break; case ATA_SERROR: reg = 2; break; default: return (EINVAL); } ATA_INTEL_LOCK(ctlr); ATA_IDX_OUTL(ch, ATA_IDX_ADDR, ((ch->unit * 2 + port) << 8) + reg); *result = ATA_IDX_INL(ch, ATA_IDX_DATA); ATA_INTEL_UNLOCK(ctlr); return (0); } static int ata_intel_sata_ahci_write(device_t dev, int port, int reg, u_int32_t value) { struct ata_pci_controller *ctlr; struct ata_channel *ch; device_t parent; u_char *smap; int offset; parent = device_get_parent(dev); ctlr = device_get_softc(parent); ch = device_get_softc(dev); port = (port == 1) ? 1 : 0; smap = ATA_INTEL_SMAP(ctlr, ch); offset = 0x100 + smap[port] * 0x80; switch (reg) { case ATA_SSTATUS: reg = 0x28; break; case ATA_SCONTROL: reg = 0x2c; break; case ATA_SERROR: reg = 0x30; break; default: return (EINVAL); } ATA_OUTL(ctlr->r_res2, offset + reg, value); return (0); } static int ata_intel_sata_cscr_write(device_t dev, int port, int reg, u_int32_t value) { struct ata_pci_controller *ctlr; struct ata_channel *ch; device_t parent; u_char *smap; parent = device_get_parent(dev); ctlr = device_get_softc(parent); ch = device_get_softc(dev); smap = ATA_INTEL_SMAP(ctlr, ch); port = (port == 1) ? 1 : 0; switch (reg) { case ATA_SSTATUS: reg = 0; break; case ATA_SERROR: reg = 1; break; case ATA_SCONTROL: reg = 2; break; default: return (EINVAL); } ATA_INTEL_LOCK(ctlr); pci_write_config(parent, 0xa0, 0x50 + smap[port] * 0x10 + reg * 4, 4); pci_write_config(parent, 0xa4, value, 4); ATA_INTEL_UNLOCK(ctlr); return (0); } static int ata_intel_sata_sidpr_write(device_t dev, int port, int reg, u_int32_t value) { struct ata_pci_controller *ctlr; struct ata_channel *ch; device_t parent; parent = device_get_parent(dev); ctlr = device_get_softc(parent); ch = device_get_softc(dev); port = (port == 1) ? 1 : 0; switch (reg) { case ATA_SSTATUS: reg = 0; break; case ATA_SCONTROL: reg = 1; break; case ATA_SERROR: reg = 2; break; default: return (EINVAL); } ATA_INTEL_LOCK(ctlr); ATA_IDX_OUTL(ch, ATA_IDX_ADDR, ((ch->unit * 2 + port) << 8) + reg); ATA_IDX_OUTL(ch, ATA_IDX_DATA, value); ATA_INTEL_UNLOCK(ctlr); return (0); } static int ata_intel_sata_sidpr_test(device_t dev) { struct ata_channel *ch = device_get_softc(dev); int port; uint32_t val; port = (ch->flags & ATA_NO_SLAVE) ? 0 : 1; for (; port >= 0; port--) { ata_intel_sata_sidpr_read(dev, port, ATA_SCONTROL, &val); if ((val & ATA_SC_IPM_MASK) == (ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER)) return (1); val |= ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER; ata_intel_sata_sidpr_write(dev, port, ATA_SCONTROL, val); ata_intel_sata_sidpr_read(dev, port, ATA_SCONTROL, &val); if ((val & ATA_SC_IPM_MASK) == (ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER)) return (1); } if (bootverbose) device_printf(dev, "SControl registers are not functional: %08x\n", val); return (0); } static int ata_intel_31244_ch_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int i; int ch_offset; ata_pci_dmainit(dev); ch_offset = 0x200 + ch->unit * 0x200; for (i = ATA_DATA; i < ATA_MAX_RES; i++) ch->r_io[i].res = ctlr->r_res2; /* setup ATA registers */ ch->r_io[ATA_DATA].offset = ch_offset + 0x00; ch->r_io[ATA_FEATURE].offset = ch_offset + 0x06; ch->r_io[ATA_COUNT].offset = ch_offset + 0x08; ch->r_io[ATA_SECTOR].offset = ch_offset + 0x0c; ch->r_io[ATA_CYL_LSB].offset = ch_offset + 0x10; ch->r_io[ATA_CYL_MSB].offset = ch_offset + 0x14; ch->r_io[ATA_DRIVE].offset = ch_offset + 0x18; ch->r_io[ATA_COMMAND].offset = ch_offset + 0x1d; ch->r_io[ATA_ERROR].offset = ch_offset + 0x04; ch->r_io[ATA_STATUS].offset = ch_offset + 0x1c; ch->r_io[ATA_ALTSTAT].offset = ch_offset + 0x28; ch->r_io[ATA_CONTROL].offset = ch_offset + 0x29; /* setup DMA registers */ ch->r_io[ATA_SSTATUS].offset = ch_offset + 0x100; ch->r_io[ATA_SERROR].offset = ch_offset + 0x104; ch->r_io[ATA_SCONTROL].offset = ch_offset + 0x108; /* setup SATA registers */ ch->r_io[ATA_BMCMD_PORT].offset = ch_offset + 0x70; ch->r_io[ATA_BMSTAT_PORT].offset = ch_offset + 0x72; ch->r_io[ATA_BMDTP_PORT].offset = ch_offset + 0x74; ch->flags |= ATA_NO_SLAVE; ch->flags |= ATA_SATA; ata_pci_hw(dev); ch->hw.status = ata_intel_31244_status; ch->hw.tf_write = ata_intel_31244_tf_write; /* enable PHY state change interrupt */ ATA_OUTL(ctlr->r_res2, 0x4, ATA_INL(ctlr->r_res2, 0x04) | (0x01 << (ch->unit << 3))); return 0; } static int ata_intel_31244_ch_detach(device_t dev) { ata_pci_dmafini(dev); return (0); } static int ata_intel_31244_status(device_t dev) { /* do we have any PHY events ? */ ata_sata_phy_check_events(dev, -1); /* any drive action to take care of ? */ return ata_pci_status(dev); } static void ata_intel_31244_tf_write(struct ata_request *request) { struct ata_channel *ch = device_get_softc(request->parent); if (request->flags & ATA_R_48BIT) { ATA_IDX_OUTW(ch, ATA_FEATURE, request->u.ata.feature); ATA_IDX_OUTW(ch, ATA_COUNT, request->u.ata.count); ATA_IDX_OUTW(ch, ATA_SECTOR, ((request->u.ata.lba >> 16) & 0xff00) | (request->u.ata.lba & 0x00ff)); ATA_IDX_OUTW(ch, ATA_CYL_LSB, ((request->u.ata.lba >> 24) & 0xff00) | ((request->u.ata.lba >> 8) & 0x00ff)); ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((request->u.ata.lba >> 32) & 0xff00) | ((request->u.ata.lba >> 16) & 0x00ff)); ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(request->unit)); } else { ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature); ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count); ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba); ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8); ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16); ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(request->unit) | ((request->u.ata.lba >> 24) & 0x0f)); } } static void ata_intel_31244_reset(device_t dev) { struct ata_channel *ch = device_get_softc(dev); if (ata_sata_phy_reset(dev, -1, 1)) ata_generic_reset(dev); else ch->devices = 0; } ATA_DECLARE_DRIVER(ata_intel); MODULE_DEPEND(ata_intel, ata_ahci, 1, 1, 1); Index: head/sys/dev/ichsmb/ichsmb_pci.c =================================================================== --- head/sys/dev/ichsmb/ichsmb_pci.c (revision 275100) +++ head/sys/dev/ichsmb/ichsmb_pci.c (revision 275101) @@ -1,263 +1,267 @@ /*- * ichsmb_pci.c * * Author: Archie Cobbs * Copyright (c) 2000 Whistle Communications, Inc. * All rights reserved. * Author: Archie Cobbs * * Subject to the following obligations and disclaimer of warranty, use and * redistribution of this software, in source or object code forms, with or * without modifications are expressly permitted by Whistle Communications; * provided, however, that: * 1. Any and all reproductions of the source or object code must include the * copyright notice above and the following disclaimer of warranties; and * 2. No rights are granted, in any manner or form, to use Whistle * Communications, Inc. trademarks, including the mark "WHISTLE * COMMUNICATIONS" on advertising, endorsements, or otherwise except as * such appears in the above copyright notice or in the software. * * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * Support for the SMBus controller logical device which is part of the * Intel 81801AA/AB/BA/CA/DC/EB (ICH/ICH[02345]) I/O controller hub chips. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* PCI unique identifiers */ #define ID_82801AA 0x24138086 #define ID_82801AB 0x24238086 #define ID_82801BA 0x24438086 #define ID_82801CA 0x24838086 #define ID_82801DC 0x24C38086 #define ID_82801EB 0x24D38086 #define ID_82801FB 0x266A8086 #define ID_82801GB 0x27da8086 #define ID_82801H 0x283e8086 #define ID_82801I 0x29308086 #define ID_82801JI 0x3a308086 #define ID_PCH 0x3b308086 #define ID_6300ESB 0x25a48086 #define ID_631xESB 0x269b8086 #define ID_DH89XXCC 0x23308086 #define ID_PATSBURG 0x1d228086 #define ID_CPT 0x1c228086 #define ID_PPT 0x1e228086 #define ID_AVOTON 0x1f3c8086 #define ID_COLETOCRK 0x23B08086 #define ID_LPT 0x8c228086 +#define ID_WCPT 0x8ca28086 #define PCIS_SERIALBUS_SMBUS_PROGIF 0x00 /* Internal functions */ static int ichsmb_pci_probe(device_t dev); static int ichsmb_pci_attach(device_t dev); /*Use generic one for now*/ #if 0 static int ichsmb_pci_detach(device_t dev); #endif /* Device methods */ static device_method_t ichsmb_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ichsmb_pci_probe), DEVMETHOD(device_attach, ichsmb_pci_attach), DEVMETHOD(device_detach, ichsmb_detach), /* SMBus methods */ DEVMETHOD(smbus_callback, ichsmb_callback), DEVMETHOD(smbus_quick, ichsmb_quick), DEVMETHOD(smbus_sendb, ichsmb_sendb), DEVMETHOD(smbus_recvb, ichsmb_recvb), DEVMETHOD(smbus_writeb, ichsmb_writeb), DEVMETHOD(smbus_writew, ichsmb_writew), DEVMETHOD(smbus_readb, ichsmb_readb), DEVMETHOD(smbus_readw, ichsmb_readw), DEVMETHOD(smbus_pcall, ichsmb_pcall), DEVMETHOD(smbus_bwrite, ichsmb_bwrite), DEVMETHOD(smbus_bread, ichsmb_bread), DEVMETHOD_END }; static driver_t ichsmb_pci_driver = { "ichsmb", ichsmb_pci_methods, sizeof(struct ichsmb_softc) }; static devclass_t ichsmb_pci_devclass; DRIVER_MODULE(ichsmb, pci, ichsmb_pci_driver, ichsmb_pci_devclass, 0, 0); static int ichsmb_pci_probe(device_t dev) { /* Check PCI identifier */ switch (pci_get_devid(dev)) { case ID_82801AA: device_set_desc(dev, "Intel 82801AA (ICH) SMBus controller"); break; case ID_82801AB: device_set_desc(dev, "Intel 82801AB (ICH0) SMBus controller"); break; case ID_82801BA: device_set_desc(dev, "Intel 82801BA (ICH2) SMBus controller"); break; case ID_82801CA: device_set_desc(dev, "Intel 82801CA (ICH3) SMBus controller"); break; case ID_82801DC: device_set_desc(dev, "Intel 82801DC (ICH4) SMBus controller"); break; case ID_82801EB: device_set_desc(dev, "Intel 82801EB (ICH5) SMBus controller"); break; case ID_82801FB: device_set_desc(dev, "Intel 82801FB (ICH6) SMBus controller"); break; case ID_82801GB: device_set_desc(dev, "Intel 82801GB (ICH7) SMBus controller"); break; case ID_82801H: device_set_desc(dev, "Intel 82801H (ICH8) SMBus controller"); break; case ID_82801I: device_set_desc(dev, "Intel 82801I (ICH9) SMBus controller"); break; case ID_82801JI: device_set_desc(dev, "Intel 82801JI (ICH10) SMBus controller"); break; case ID_PCH: device_set_desc(dev, "Intel PCH SMBus controller"); break; case ID_6300ESB: device_set_desc(dev, "Intel 6300ESB (ICH) SMBus controller"); break; case ID_631xESB: device_set_desc(dev, "Intel 631xESB/6321ESB (ESB2) SMBus controller"); break; case ID_DH89XXCC: device_set_desc(dev, "Intel DH89xxCC SMBus controller"); break; case ID_PATSBURG: device_set_desc(dev, "Intel Patsburg SMBus controller"); break; case ID_CPT: device_set_desc(dev, "Intel Cougar Point SMBus controller"); break; case ID_PPT: device_set_desc(dev, "Intel Panther Point SMBus controller"); break; case ID_AVOTON: device_set_desc(dev, "Intel Avoton SMBus controller"); break; case ID_LPT: device_set_desc(dev, "Intel Lynx Point SMBus controller"); + break; + case ID_WCPT: + device_set_desc(dev, "Intel Wildcat Point SMBus controller"); break; case ID_COLETOCRK: device_set_desc(dev, "Intel Coleto Creek SMBus controller"); break; default: return (ENXIO); } /* Done */ return (ichsmb_probe(dev)); } static int ichsmb_pci_attach(device_t dev) { const sc_p sc = device_get_softc(dev); int error; /* Initialize private state */ bzero(sc, sizeof(*sc)); sc->ich_cmd = -1; sc->dev = dev; /* Allocate an I/O range */ sc->io_rid = ICH_SMB_BASE; sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->io_rid, 0, ~0, 16, RF_ACTIVE); if (sc->io_res == NULL) sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->io_rid, 0ul, ~0ul, 32, RF_ACTIVE); if (sc->io_res == NULL) { device_printf(dev, "can't map I/O\n"); error = ENXIO; goto fail; } /* Allocate interrupt */ sc->irq_rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_ACTIVE | RF_SHAREABLE); if (sc->irq_res == NULL) { device_printf(dev, "can't get IRQ\n"); error = ENXIO; goto fail; } /* Enable device */ pci_write_config(dev, ICH_HOSTC, ICH_HOSTC_HST_EN, 1); /* Done */ error = ichsmb_attach(dev); if (error) goto fail; return (0); fail: /* Attach failed, release resources */ ichsmb_release_resources(sc); return (error); } MODULE_DEPEND(ichsmb, pci, 1, 1, 1); MODULE_DEPEND(ichsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); MODULE_VERSION(ichsmb, 1); Index: head/sys/dev/ichwd/ichwd.c =================================================================== --- head/sys/dev/ichwd/ichwd.c (revision 275100) +++ head/sys/dev/ichwd/ichwd.c (revision 275101) @@ -1,639 +1,642 @@ /*- * Copyright (c) 2004 Texas A&M University * All rights reserved. * * Developer: Wm. Daryl Hawkins * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Intel ICH Watchdog Timer (WDT) driver * * Originally developed by Wm. Daryl Hawkins of Texas A&M * Heavily modified by * * This is a tricky one. The ICH WDT can't be treated as a regular PCI * device as it's actually an integrated function of the ICH LPC interface * bridge. Detection is also awkward, because we can only infer the * presence of the watchdog timer from the fact that the machine has an * ICH chipset, or, on ACPI 2.x systems, by the presence of the 'WDDT' * ACPI table (although this driver does not support the ACPI detection * method). * * There is one slight problem on non-ACPI or ACPI 1.x systems: we have no * way of knowing if the WDT is permanently disabled (either by the BIOS * or in hardware). * * The WDT is programmed through I/O registers in the ACPI I/O space. * Intel swears it's always at offset 0x60, so we use that. * * For details about the ICH WDT, see Intel Application Note AP-725 * (document no. 292273-001). The WDT is also described in the individual * chipset datasheets, e.g. Intel82801EB ICH5 / 82801ER ICH5R Datasheet * (document no. 252516-001) sections 9.10 and 9.11. * * ICH6/7/8 support by Takeharu KATO */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include static struct ichwd_device ichwd_devices[] = { { DEVICEID_82801AA, "Intel 82801AA watchdog timer", 1 }, { DEVICEID_82801AB, "Intel 82801AB watchdog timer", 1 }, { DEVICEID_82801BA, "Intel 82801BA watchdog timer", 2 }, { DEVICEID_82801BAM, "Intel 82801BAM watchdog timer", 2 }, { DEVICEID_82801CA, "Intel 82801CA watchdog timer", 3 }, { DEVICEID_82801CAM, "Intel 82801CAM watchdog timer", 3 }, { DEVICEID_82801DB, "Intel 82801DB watchdog timer", 4 }, { DEVICEID_82801DBM, "Intel 82801DBM watchdog timer", 4 }, { DEVICEID_82801E, "Intel 82801E watchdog timer", 5 }, { DEVICEID_82801EB, "Intel 82801EB watchdog timer", 5 }, { DEVICEID_82801EBR, "Intel 82801EB/ER watchdog timer", 5 }, { DEVICEID_6300ESB, "Intel 6300ESB watchdog timer", 5 }, { DEVICEID_82801FBR, "Intel 82801FB/FR watchdog timer", 6 }, { DEVICEID_ICH6M, "Intel ICH6M watchdog timer", 6 }, { DEVICEID_ICH6W, "Intel ICH6W watchdog timer", 6 }, { DEVICEID_ICH7, "Intel ICH7 watchdog timer", 7 }, { DEVICEID_ICH7DH, "Intel ICH7DH watchdog timer", 7 }, { DEVICEID_ICH7M, "Intel ICH7M watchdog timer", 7 }, { DEVICEID_ICH7MDH, "Intel ICH7MDH watchdog timer", 7 }, { DEVICEID_NM10, "Intel NM10 watchdog timer", 7 }, { DEVICEID_ICH8, "Intel ICH8 watchdog timer", 8 }, { DEVICEID_ICH8DH, "Intel ICH8DH watchdog timer", 8 }, { DEVICEID_ICH8DO, "Intel ICH8DO watchdog timer", 8 }, { DEVICEID_ICH8M, "Intel ICH8M watchdog timer", 8 }, { DEVICEID_ICH8ME, "Intel ICH8M-E watchdog timer", 8 }, { DEVICEID_63XXESB, "Intel 63XXESB watchdog timer", 8 }, { DEVICEID_ICH9, "Intel ICH9 watchdog timer", 9 }, { DEVICEID_ICH9DH, "Intel ICH9DH watchdog timer", 9 }, { DEVICEID_ICH9DO, "Intel ICH9DO watchdog timer", 9 }, { DEVICEID_ICH9M, "Intel ICH9M watchdog timer", 9 }, { DEVICEID_ICH9ME, "Intel ICH9M-E watchdog timer", 9 }, { DEVICEID_ICH9R, "Intel ICH9R watchdog timer", 9 }, { DEVICEID_ICH10, "Intel ICH10 watchdog timer", 10 }, { DEVICEID_ICH10D, "Intel ICH10D watchdog timer", 10 }, { DEVICEID_ICH10DO, "Intel ICH10DO watchdog timer", 10 }, { DEVICEID_ICH10R, "Intel ICH10R watchdog timer", 10 }, { DEVICEID_PCH, "Intel PCH watchdog timer", 10 }, { DEVICEID_PCHM, "Intel PCH watchdog timer", 10 }, { DEVICEID_P55, "Intel P55 watchdog timer", 10 }, { DEVICEID_PM55, "Intel PM55 watchdog timer", 10 }, { DEVICEID_H55, "Intel H55 watchdog timer", 10 }, { DEVICEID_QM57, "Intel QM57 watchdog timer", 10 }, { DEVICEID_H57, "Intel H57 watchdog timer", 10 }, { DEVICEID_HM55, "Intel HM55 watchdog timer", 10 }, { DEVICEID_Q57, "Intel Q57 watchdog timer", 10 }, { DEVICEID_HM57, "Intel HM57 watchdog timer", 10 }, { DEVICEID_PCHMSFF, "Intel PCHMSFF watchdog timer", 10 }, { DEVICEID_QS57, "Intel QS57 watchdog timer", 10 }, { DEVICEID_3400, "Intel 3400 watchdog timer", 10 }, { DEVICEID_3420, "Intel 3420 watchdog timer", 10 }, { DEVICEID_3450, "Intel 3450 watchdog timer", 10 }, { DEVICEID_CPT0, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT1, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT2, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT3, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT4, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT5, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT6, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT7, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT8, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT9, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT10, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT11, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT12, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT13, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT14, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT15, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT16, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT17, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT18, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT19, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT20, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT21, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT22, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT23, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT23, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT25, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT26, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT27, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT28, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT29, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT30, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_CPT31, "Intel Cougar Point watchdog timer", 10 }, { DEVICEID_PATSBURG_LPC1, "Intel Patsburg watchdog timer", 10 }, { DEVICEID_PATSBURG_LPC2, "Intel Patsburg watchdog timer", 10 }, { DEVICEID_PPT0, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT1, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT2, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT3, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT4, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT5, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT6, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT7, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT8, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT9, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT10, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT11, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT12, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT13, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT14, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT15, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT16, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT17, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT18, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT19, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT20, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT21, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT22, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT23, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT24, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT25, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT26, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT27, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT28, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT29, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT30, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_PPT31, "Intel Panther Point watchdog timer", 10 }, { DEVICEID_LPT0, "Intel Lynx Point watchdog timer", 10 }, { DEVICEID_LPT1, "Intel Lynx Point watchdog timer", 10 }, { DEVICEID_LPT2, "Intel Lynx Point watchdog timer", 10 }, + { DEVICEID_WCPT2, "Intel Wildcat Point watchdog timer", 10 }, + { DEVICEID_WCPT4, "Intel Wildcat Point watchdog timer", 10 }, + { DEVICEID_WCPT6, "Intel Wildcat Point watchdog timer", 10 }, { DEVICEID_DH89XXCC_LPC, "Intel DH89xxCC watchdog timer", 10 }, { DEVICEID_COLETOCRK_LPC, "Intel Coleto Creek watchdog timer", 10 }, { 0, NULL, 0 }, }; static devclass_t ichwd_devclass; #define ichwd_read_tco_1(sc, off) \ bus_read_1((sc)->tco_res, (off)) #define ichwd_read_tco_2(sc, off) \ bus_read_2((sc)->tco_res, (off)) #define ichwd_read_tco_4(sc, off) \ bus_read_4((sc)->tco_res, (off)) #define ichwd_read_smi_4(sc, off) \ bus_read_4((sc)->smi_res, (off)) #define ichwd_read_gcs_4(sc, off) \ bus_read_4((sc)->gcs_res, (off)) #define ichwd_write_tco_1(sc, off, val) \ bus_write_1((sc)->tco_res, (off), (val)) #define ichwd_write_tco_2(sc, off, val) \ bus_write_2((sc)->tco_res, (off), (val)) #define ichwd_write_tco_4(sc, off, val) \ bus_write_4((sc)->tco_res, (off), (val)) #define ichwd_write_smi_4(sc, off, val) \ bus_write_4((sc)->smi_res, (off), (val)) #define ichwd_write_gcs_4(sc, off, val) \ bus_write_4((sc)->gcs_res, (off), (val)) #define ichwd_verbose_printf(dev, ...) \ do { \ if (bootverbose) \ device_printf(dev, __VA_ARGS__);\ } while (0) /* * Disable the watchdog timeout SMI handler. * * Apparently, some BIOSes install handlers that reset or disable the * watchdog timer instead of resetting the system, so we disable the SMI * (by clearing the SMI_TCO_EN bit of the SMI_EN register) to prevent this * from happening. */ static __inline void ichwd_smi_disable(struct ichwd_softc *sc) { ichwd_write_smi_4(sc, SMI_EN, ichwd_read_smi_4(sc, SMI_EN) & ~SMI_TCO_EN); } /* * Enable the watchdog timeout SMI handler. See above for details. */ static __inline void ichwd_smi_enable(struct ichwd_softc *sc) { ichwd_write_smi_4(sc, SMI_EN, ichwd_read_smi_4(sc, SMI_EN) | SMI_TCO_EN); } /* * Check if the watchdog SMI triggering is enabled. */ static __inline int ichwd_smi_is_enabled(struct ichwd_softc *sc) { return ((ichwd_read_smi_4(sc, SMI_EN) & SMI_TCO_EN) != 0); } /* * Reset the watchdog status bits. */ static __inline void ichwd_sts_reset(struct ichwd_softc *sc) { /* * The watchdog status bits are set to 1 by the hardware to * indicate various conditions. They can be cleared by software * by writing a 1, not a 0. */ ichwd_write_tco_2(sc, TCO1_STS, TCO_TIMEOUT); /* * According to Intel's docs, clearing SECOND_TO_STS and BOOT_STS must * be done in two separate operations. */ ichwd_write_tco_2(sc, TCO2_STS, TCO_SECOND_TO_STS); ichwd_write_tco_2(sc, TCO2_STS, TCO_BOOT_STS); } /* * Enable the watchdog timer by clearing the TCO_TMR_HALT bit in the * TCO1_CNT register. This is complicated by the need to preserve bit 9 * of that same register, and the requirement that all other bits must be * written back as zero. */ static __inline void ichwd_tmr_enable(struct ichwd_softc *sc) { uint16_t cnt; cnt = ichwd_read_tco_2(sc, TCO1_CNT) & TCO_CNT_PRESERVE; ichwd_write_tco_2(sc, TCO1_CNT, cnt & ~TCO_TMR_HALT); sc->active = 1; ichwd_verbose_printf(sc->device, "timer enabled\n"); } /* * Disable the watchdog timer. See above for details. */ static __inline void ichwd_tmr_disable(struct ichwd_softc *sc) { uint16_t cnt; cnt = ichwd_read_tco_2(sc, TCO1_CNT) & TCO_CNT_PRESERVE; ichwd_write_tco_2(sc, TCO1_CNT, cnt | TCO_TMR_HALT); sc->active = 0; ichwd_verbose_printf(sc->device, "timer disabled\n"); } /* * Reload the watchdog timer: writing anything to any of the lower five * bits of the TCO_RLD register reloads the timer from the last value * written to TCO_TMR. */ static __inline void ichwd_tmr_reload(struct ichwd_softc *sc) { if (sc->ich_version <= 5) ichwd_write_tco_1(sc, TCO_RLD, 1); else ichwd_write_tco_2(sc, TCO_RLD, 1); } /* * Set the initial timeout value. Note that this must always be followed * by a reload. */ static __inline void ichwd_tmr_set(struct ichwd_softc *sc, unsigned int timeout) { if (timeout < TCO_RLD_TMR_MIN) timeout = TCO_RLD_TMR_MIN; if (sc->ich_version <= 5) { uint8_t tmr_val8 = ichwd_read_tco_1(sc, TCO_TMR1); tmr_val8 &= (~TCO_RLD1_TMR_MAX & 0xff); if (timeout > TCO_RLD1_TMR_MAX) timeout = TCO_RLD1_TMR_MAX; tmr_val8 |= timeout; ichwd_write_tco_1(sc, TCO_TMR1, tmr_val8); } else { uint16_t tmr_val16 = ichwd_read_tco_2(sc, TCO_TMR2); tmr_val16 &= (~TCO_RLD2_TMR_MAX & 0xffff); if (timeout > TCO_RLD2_TMR_MAX) timeout = TCO_RLD2_TMR_MAX; tmr_val16 |= timeout; ichwd_write_tco_2(sc, TCO_TMR2, tmr_val16); } sc->timeout = timeout; ichwd_verbose_printf(sc->device, "timeout set to %u ticks\n", timeout); } static __inline int ichwd_clear_noreboot(struct ichwd_softc *sc) { uint32_t status; int rc = 0; /* try to clear the NO_REBOOT bit */ if (sc->ich_version <= 5) { status = pci_read_config(sc->ich, ICH_GEN_STA, 1); status &= ~ICH_GEN_STA_NO_REBOOT; pci_write_config(sc->ich, ICH_GEN_STA, status, 1); status = pci_read_config(sc->ich, ICH_GEN_STA, 1); if (status & ICH_GEN_STA_NO_REBOOT) rc = EIO; } else { status = ichwd_read_gcs_4(sc, 0); status &= ~ICH_GCS_NO_REBOOT; ichwd_write_gcs_4(sc, 0, status); status = ichwd_read_gcs_4(sc, 0); if (status & ICH_GCS_NO_REBOOT) rc = EIO; } if (rc) device_printf(sc->device, "ICH WDT present but disabled in BIOS or hardware\n"); return (rc); } /* * Watchdog event handler - called by the framework to enable or disable * the watchdog or change the initial timeout value. */ static void ichwd_event(void *arg, unsigned int cmd, int *error) { struct ichwd_softc *sc = arg; unsigned int timeout; /* convert from power-of-two-ns to WDT ticks */ cmd &= WD_INTERVAL; timeout = ((uint64_t)1 << cmd) / ICHWD_TICK; if (cmd) { if (!sc->active) ichwd_tmr_enable(sc); if (timeout != sc->timeout) ichwd_tmr_set(sc, timeout); ichwd_tmr_reload(sc); *error = 0; } else { if (sc->active) ichwd_tmr_disable(sc); } } static device_t ichwd_find_ich_lpc_bridge(struct ichwd_device **id_p) { struct ichwd_device *id; device_t ich = NULL; /* look for an ICH LPC interface bridge */ for (id = ichwd_devices; id->desc != NULL; ++id) if ((ich = pci_find_device(VENDORID_INTEL, id->device)) != NULL) break; if (ich == NULL) return (NULL); ichwd_verbose_printf(ich, "found ICH%d or equivalent chipset: %s\n", id->version, id->desc); if (id_p) *id_p = id; return (ich); } /* * Look for an ICH LPC interface bridge. If one is found, register an * ichwd device. There can be only one. */ static void ichwd_identify(driver_t *driver, device_t parent) { struct ichwd_device *id_p; device_t ich = NULL; device_t dev; uint32_t rcba; int rc; ich = ichwd_find_ich_lpc_bridge(&id_p); if (ich == NULL) return; /* good, add child to bus */ if ((dev = device_find_child(parent, driver->name, 0)) == NULL) dev = BUS_ADD_CHILD(parent, 0, driver->name, 0); if (dev == NULL) return; device_set_desc_copy(dev, id_p->desc); if (id_p->version >= 6) { /* get RCBA (root complex base address) */ rcba = pci_read_config(ich, ICH_RCBA, 4); rc = bus_set_resource(ich, SYS_RES_MEMORY, 0, (rcba & 0xffffc000) + ICH_GCS_OFFSET, ICH_GCS_SIZE); if (rc) ichwd_verbose_printf(dev, "Can not set memory resource for RCBA\n"); } } static int ichwd_probe(device_t dev) { /* Do not claim some ISA PnP device by accident. */ if (isa_get_logicalid(dev) != 0) return (ENXIO); return (0); } static int ichwd_attach(device_t dev) { struct ichwd_softc *sc; struct ichwd_device *id_p; device_t ich; unsigned int pmbase = 0; sc = device_get_softc(dev); sc->device = dev; ich = ichwd_find_ich_lpc_bridge(&id_p); if (ich == NULL) { device_printf(sc->device, "Can not find ICH device.\n"); goto fail; } sc->ich = ich; sc->ich_version = id_p->version; /* get ACPI base address */ pmbase = pci_read_config(ich, ICH_PMBASE, 2) & ICH_PMBASE_MASK; if (pmbase == 0) { device_printf(dev, "ICH PMBASE register is empty\n"); goto fail; } /* allocate I/O register space */ sc->smi_rid = 0; sc->smi_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->smi_rid, pmbase + SMI_BASE, pmbase + SMI_BASE + SMI_LEN - 1, SMI_LEN, RF_ACTIVE | RF_SHAREABLE); if (sc->smi_res == NULL) { device_printf(dev, "unable to reserve SMI registers\n"); goto fail; } sc->tco_rid = 1; sc->tco_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->tco_rid, pmbase + TCO_BASE, pmbase + TCO_BASE + TCO_LEN - 1, TCO_LEN, RF_ACTIVE | RF_SHAREABLE); if (sc->tco_res == NULL) { device_printf(dev, "unable to reserve TCO registers\n"); goto fail; } sc->gcs_rid = 0; if (sc->ich_version >= 6) { sc->gcs_res = bus_alloc_resource_any(ich, SYS_RES_MEMORY, &sc->gcs_rid, RF_ACTIVE|RF_SHAREABLE); if (sc->gcs_res == NULL) { device_printf(dev, "unable to reserve GCS registers\n"); goto fail; } } if (ichwd_clear_noreboot(sc) != 0) goto fail; ichwd_verbose_printf(dev, "%s (ICH%d or equivalent)\n", device_get_desc(dev), sc->ich_version); /* * Determine if we are coming up after a watchdog-induced reset. Some * BIOSes may clear this bit at bootup, preventing us from reporting * this case on such systems. We clear this bit in ichwd_sts_reset(). */ if ((ichwd_read_tco_2(sc, TCO2_STS) & TCO_SECOND_TO_STS) != 0) device_printf(dev, "resuming after hardware watchdog timeout\n"); /* reset the watchdog status registers */ ichwd_sts_reset(sc); /* make sure the WDT starts out inactive */ ichwd_tmr_disable(sc); /* register the watchdog event handler */ sc->ev_tag = EVENTHANDLER_REGISTER(watchdog_list, ichwd_event, sc, 0); /* disable the SMI handler */ sc->smi_enabled = ichwd_smi_is_enabled(sc); ichwd_smi_disable(sc); return (0); fail: sc = device_get_softc(dev); if (sc->tco_res != NULL) bus_release_resource(dev, SYS_RES_IOPORT, sc->tco_rid, sc->tco_res); if (sc->smi_res != NULL) bus_release_resource(dev, SYS_RES_IOPORT, sc->smi_rid, sc->smi_res); if (sc->gcs_res != NULL) bus_release_resource(ich, SYS_RES_MEMORY, sc->gcs_rid, sc->gcs_res); return (ENXIO); } static int ichwd_detach(device_t dev) { struct ichwd_softc *sc; device_t ich = NULL; sc = device_get_softc(dev); /* halt the watchdog timer */ if (sc->active) ichwd_tmr_disable(sc); /* enable the SMI handler */ if (sc->smi_enabled != 0) ichwd_smi_enable(sc); /* deregister event handler */ if (sc->ev_tag != NULL) EVENTHANDLER_DEREGISTER(watchdog_list, sc->ev_tag); sc->ev_tag = NULL; /* reset the watchdog status registers */ ichwd_sts_reset(sc); /* deallocate I/O register space */ bus_release_resource(dev, SYS_RES_IOPORT, sc->tco_rid, sc->tco_res); bus_release_resource(dev, SYS_RES_IOPORT, sc->smi_rid, sc->smi_res); /* deallocate memory resource */ ich = ichwd_find_ich_lpc_bridge(NULL); if (sc->gcs_res && ich) bus_release_resource(ich, SYS_RES_MEMORY, sc->gcs_rid, sc->gcs_res); return (0); } static device_method_t ichwd_methods[] = { DEVMETHOD(device_identify, ichwd_identify), DEVMETHOD(device_probe, ichwd_probe), DEVMETHOD(device_attach, ichwd_attach), DEVMETHOD(device_detach, ichwd_detach), DEVMETHOD(device_shutdown, ichwd_detach), {0,0} }; static driver_t ichwd_driver = { "ichwd", ichwd_methods, sizeof(struct ichwd_softc), }; DRIVER_MODULE(ichwd, isa, ichwd_driver, ichwd_devclass, NULL, NULL); Index: head/sys/dev/ichwd/ichwd.h =================================================================== --- head/sys/dev/ichwd/ichwd.h (revision 275100) +++ head/sys/dev/ichwd/ichwd.h (revision 275101) @@ -1,285 +1,288 @@ /*- * Copyright (c) 2004 Texas A&M University * All rights reserved. * * Developer: Wm. Daryl Hawkins * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _ICHWD_H_ #define _ICHWD_H_ struct ichwd_device { uint16_t device; char *desc; unsigned int version; }; struct ichwd_softc { device_t device; device_t ich; int ich_version; int active; unsigned int timeout; int smi_enabled; int smi_rid; struct resource *smi_res; int tco_rid; struct resource *tco_res; int gcs_rid; struct resource *gcs_res; eventhandler_tag ev_tag; }; #define VENDORID_INTEL 0x8086 #define DEVICEID_CPT0 0x1c40 #define DEVICEID_CPT1 0x1c41 #define DEVICEID_CPT2 0x1c42 #define DEVICEID_CPT3 0x1c43 #define DEVICEID_CPT4 0x1c44 #define DEVICEID_CPT5 0x1c45 #define DEVICEID_CPT6 0x1c46 #define DEVICEID_CPT7 0x1c47 #define DEVICEID_CPT8 0x1c48 #define DEVICEID_CPT9 0x1c49 #define DEVICEID_CPT10 0x1c4a #define DEVICEID_CPT11 0x1c4b #define DEVICEID_CPT12 0x1c4c #define DEVICEID_CPT13 0x1c4d #define DEVICEID_CPT14 0x1c4e #define DEVICEID_CPT15 0x1c4f #define DEVICEID_CPT16 0x1c50 #define DEVICEID_CPT17 0x1c51 #define DEVICEID_CPT18 0x1c52 #define DEVICEID_CPT19 0x1c53 #define DEVICEID_CPT20 0x1c54 #define DEVICEID_CPT21 0x1c55 #define DEVICEID_CPT22 0x1c56 #define DEVICEID_CPT23 0x1c57 #define DEVICEID_CPT24 0x1c58 #define DEVICEID_CPT25 0x1c59 #define DEVICEID_CPT26 0x1c5a #define DEVICEID_CPT27 0x1c5b #define DEVICEID_CPT28 0x1c5c #define DEVICEID_CPT29 0x1c5d #define DEVICEID_CPT30 0x1c5e #define DEVICEID_CPT31 0x1c5f #define DEVICEID_PATSBURG_LPC1 0x1d40 #define DEVICEID_PATSBURG_LPC2 0x1d41 #define DEVICEID_PPT0 0x1e40 #define DEVICEID_PPT1 0x1e41 #define DEVICEID_PPT2 0x1e42 #define DEVICEID_PPT3 0x1e43 #define DEVICEID_PPT4 0x1e44 #define DEVICEID_PPT5 0x1e45 #define DEVICEID_PPT6 0x1e46 #define DEVICEID_PPT7 0x1e47 #define DEVICEID_PPT8 0x1e48 #define DEVICEID_PPT9 0x1e49 #define DEVICEID_PPT10 0x1e4a #define DEVICEID_PPT11 0x1e4b #define DEVICEID_PPT12 0x1e4c #define DEVICEID_PPT13 0x1e4d #define DEVICEID_PPT14 0x1e4e #define DEVICEID_PPT15 0x1e4f #define DEVICEID_PPT16 0x1e50 #define DEVICEID_PPT17 0x1e51 #define DEVICEID_PPT18 0x1e52 #define DEVICEID_PPT19 0x1e53 #define DEVICEID_PPT20 0x1e54 #define DEVICEID_PPT21 0x1e55 #define DEVICEID_PPT22 0x1e56 #define DEVICEID_PPT23 0x1e57 #define DEVICEID_PPT24 0x1e58 #define DEVICEID_PPT25 0x1e59 #define DEVICEID_PPT26 0x1e5a #define DEVICEID_PPT27 0x1e5b #define DEVICEID_PPT28 0x1e5c #define DEVICEID_PPT29 0x1e5d #define DEVICEID_PPT30 0x1e5e #define DEVICEID_PPT31 0x1e5f #define DEVICEID_DH89XXCC_LPC 0x2310 #define DEVICEID_COLETOCRK_LPC 0x2390 #define DEVICEID_82801AA 0x2410 #define DEVICEID_82801AB 0x2420 #define DEVICEID_82801BA 0x2440 #define DEVICEID_82801BAM 0x244c #define DEVICEID_82801CA 0x2480 #define DEVICEID_82801CAM 0x248c #define DEVICEID_82801DB 0x24c0 #define DEVICEID_82801DBM 0x24cc #define DEVICEID_82801E 0x2450 #define DEVICEID_82801EB 0x24dc #define DEVICEID_82801EBR 0x24d0 #define DEVICEID_6300ESB 0x25a1 #define DEVICEID_82801FBR 0x2640 #define DEVICEID_ICH6M 0x2641 #define DEVICEID_ICH6W 0x2642 #define DEVICEID_63XXESB 0x2670 #define DEVICEID_ICH7 0x27b8 #define DEVICEID_ICH7DH 0x27b0 #define DEVICEID_ICH7M 0x27b9 #define DEVICEID_NM10 0x27bc #define DEVICEID_ICH7MDH 0x27bd #define DEVICEID_ICH8 0x2810 #define DEVICEID_ICH8DH 0x2812 #define DEVICEID_ICH8DO 0x2814 #define DEVICEID_ICH8M 0x2815 #define DEVICEID_ICH8ME 0x2811 #define DEVICEID_ICH9 0x2918 #define DEVICEID_ICH9DH 0x2912 #define DEVICEID_ICH9DO 0x2914 #define DEVICEID_ICH9M 0x2919 #define DEVICEID_ICH9ME 0x2917 #define DEVICEID_ICH9R 0x2916 #define DEVICEID_ICH10 0x3a18 #define DEVICEID_ICH10D 0x3a1a #define DEVICEID_ICH10DO 0x3a14 #define DEVICEID_ICH10R 0x3a16 #define DEVICEID_PCH 0x3b00 #define DEVICEID_PCHM 0x3b01 #define DEVICEID_P55 0x3b02 #define DEVICEID_PM55 0x3b03 #define DEVICEID_H55 0x3b06 #define DEVICEID_QM57 0x3b07 #define DEVICEID_H57 0x3b08 #define DEVICEID_HM55 0x3b09 #define DEVICEID_Q57 0x3b0a #define DEVICEID_HM57 0x3b0b #define DEVICEID_PCHMSFF 0x3b0d #define DEVICEID_QS57 0x3b0f #define DEVICEID_3400 0x3b12 #define DEVICEID_3420 0x3b14 #define DEVICEID_3450 0x3b16 #define DEVICEID_LPT0 0x8c40 #define DEVICEID_LPT1 0x8c41 #define DEVICEID_LPT2 0x8c42 #define DEVICEID_LPT3 0x8c43 #define DEVICEID_LPT4 0x8c44 #define DEVICEID_LPT5 0x8c45 #define DEVICEID_LPT6 0x8c46 #define DEVICEID_LPT7 0x8c47 #define DEVICEID_LPT8 0x8c48 #define DEVICEID_LPT9 0x8c49 #define DEVICEID_LPT10 0x8c4a #define DEVICEID_LPT11 0x8c4b #define DEVICEID_LPT12 0x8c4c #define DEVICEID_LPT13 0x8c4d #define DEVICEID_LPT14 0x8c4e #define DEVICEID_LPT15 0x8c4f #define DEVICEID_LPT16 0x8c50 #define DEVICEID_LPT17 0x8c51 #define DEVICEID_LPT18 0x8c52 #define DEVICEID_LPT19 0x8c53 #define DEVICEID_LPT20 0x8c54 #define DEVICEID_LPT21 0x8c55 #define DEVICEID_LPT22 0x8c56 #define DEVICEID_LPT23 0x8c57 #define DEVICEID_LPT24 0x8c58 #define DEVICEID_LPT25 0x8c59 #define DEVICEID_LPT26 0x8c5a #define DEVICEID_LPT27 0x8c5b #define DEVICEID_LPT28 0x8c5c #define DEVICEID_LPT29 0x8c5d #define DEVICEID_LPT30 0x8c5e #define DEVICEID_LPT31 0x8c5f +#define DEVICEID_WCPT2 0x8cc2 +#define DEVICEID_WCPT4 0x8cc4 +#define DEVICEID_WCPT6 0x8cc6 /* ICH LPC Interface Bridge Registers (ICH5 and older) */ #define ICH_GEN_STA 0xd4 #define ICH_GEN_STA_NO_REBOOT 0x02 #define ICH_PMBASE 0x40 /* ACPI base address register */ #define ICH_PMBASE_MASK 0x7f80 /* bits 7-15 */ /* ICH Chipset Configuration Registers (ICH6 and newer) */ #define ICH_RCBA 0xf0 #define ICH_GCS_OFFSET 0x3410 #define ICH_GCS_SIZE 0x4 #define ICH_GCS_NO_REBOOT 0x20 /* register names and locations (relative to PMBASE) */ #define SMI_BASE 0x30 /* base address for SMI registers */ #define SMI_LEN 0x08 #define SMI_EN 0x00 /* SMI Control and Enable Register */ #define SMI_STS 0x04 /* SMI Status Register */ #define TCO_BASE 0x60 /* base address for TCO registers */ #define TCO_LEN 0x20 #define TCO_RLD 0x00 /* TCO Reload and Current Value */ #define TCO_TMR1 0x01 /* TCO Timer Initial Value (ICH5 and older, 8 bits) */ #define TCO_TMR2 0x12 /* TCO Timer Initial Value (ICH6 and newer, 16 bits) */ #define TCO_DAT_IN 0x02 /* TCO Data In (DO NOT USE) */ #define TCO_DAT_OUT 0x03 /* TCO Data Out (DO NOT USE) */ #define TCO1_STS 0x04 /* TCO Status 1 */ #define TCO2_STS 0x06 /* TCO Status 2 */ #define TCO1_CNT 0x08 /* TCO Control 1 */ #define TCO2_CNT 0x08 /* TCO Control 2 */ #define TCO_MESSAGE1 0x0c /* TCO Message 1 */ #define TCO_MESSAGE2 0x0d /* TCO Message 2 */ /* bit definitions for SMI_EN and SMI_STS */ #define SMI_TCO_EN 0x2000 #define SMI_TCO_STS 0x2000 #define SMI_GBL_EN 0x0001 /* timer value mask for TCO_RLD and TCO_TMR */ #define TCO_TIMER_MASK 0x1f /* status bits for TCO1_STS */ #define TCO_NEWCENTURY 0x80 /* set for RTC year roll over (99 to 00) */ #define TCO_TIMEOUT 0x08 /* timed out */ #define TCO_INT_STS 0x04 /* data out (DO NOT USE) */ #define TCO_SMI_STS 0x02 /* data in (DO NOT USE) */ /* status bits for TCO2_STS */ #define TCO_BOOT_STS 0x04 /* failed to come out of reset */ #define TCO_SECOND_TO_STS 0x02 /* ran down twice */ /* control bits for TCO1_CNT */ #define TCO_TMR_HALT 0x0800 /* clear to enable WDT */ #define TCO_NMI2SMI_EN 0x0200 /* convert NMIs to SMIs */ #define TCO_CNT_PRESERVE TCO_NMI2SMI_EN /* preserve these bits */ #define TCO_NMI_NOW 0x0100 /* trigger an NMI */ /* * Masks for the TCO timer value field in TCO_RLD. * If the datasheets are to be believed, the minimum value actually varies * from chipset to chipset - 4 for ICH5 and 2 for all other chipsets. * I suspect this is a bug in the ICH5 datasheet and that the minimum is * uniformly 2, but I'd rather err on the side of caution. */ #define TCO_RLD_TMR_MIN 0x0004 #define TCO_RLD1_TMR_MAX 0x003f #define TCO_RLD2_TMR_MAX 0x03ff /* approximate length in nanoseconds of one WDT tick (about 0.6 sec) */ #define ICHWD_TICK 600000000 #endif Index: head/sys/dev/sound/pci/hda/hdac.c =================================================================== --- head/sys/dev/sound/pci/hda/hdac.c (revision 275100) +++ head/sys/dev/sound/pci/hda/hdac.c (revision 275101) @@ -1,2087 +1,2088 @@ /*- * Copyright (c) 2006 Stephane E. Potvin * Copyright (c) 2006 Ariff Abdullah * Copyright (c) 2008-2012 Alexander Motin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Intel High Definition Audio (Controller) driver for FreeBSD. */ #ifdef HAVE_KERNEL_OPTION_HEADERS #include "opt_snd.h" #endif #include #include #include #include #include #include #include #include #include #define HDA_DRV_TEST_REV "20120126_0002" SND_DECLARE_FILE("$FreeBSD$"); #define hdac_lock(sc) snd_mtxlock((sc)->lock) #define hdac_unlock(sc) snd_mtxunlock((sc)->lock) #define hdac_lockassert(sc) snd_mtxassert((sc)->lock) #define hdac_lockowned(sc) mtx_owned((sc)->lock) #define HDAC_QUIRK_64BIT (1 << 0) #define HDAC_QUIRK_DMAPOS (1 << 1) #define HDAC_QUIRK_MSI (1 << 2) static const struct { const char *key; uint32_t value; } hdac_quirks_tab[] = { { "64bit", HDAC_QUIRK_DMAPOS }, { "dmapos", HDAC_QUIRK_DMAPOS }, { "msi", HDAC_QUIRK_MSI }, }; MALLOC_DEFINE(M_HDAC, "hdac", "HDA Controller"); static const struct { uint32_t model; const char *desc; char quirks_on; char quirks_off; } hdac_devices[] = { { HDA_INTEL_OAK, "Intel Oaktrail", 0, 0 }, { HDA_INTEL_BAY, "Intel BayTrail", 0, 0 }, { HDA_INTEL_HSW1, "Intel Haswell", 0, 0 }, { HDA_INTEL_HSW2, "Intel Haswell", 0, 0 }, { HDA_INTEL_HSW3, "Intel Haswell", 0, 0 }, { HDA_INTEL_CPT, "Intel Cougar Point", 0, 0 }, { HDA_INTEL_PATSBURG,"Intel Patsburg", 0, 0 }, { HDA_INTEL_PPT1, "Intel Panther Point", 0, 0 }, { HDA_INTEL_LPT1, "Intel Lynx Point", 0, 0 }, { HDA_INTEL_LPT2, "Intel Lynx Point", 0, 0 }, + { HDA_INTEL_WCPT, "Intel Wildcat Point", 0, 0 }, { HDA_INTEL_WELLS1, "Intel Wellsburg", 0, 0 }, { HDA_INTEL_WELLS2, "Intel Wellsburg", 0, 0 }, { HDA_INTEL_LPTLP1, "Intel Lynx Point-LP", 0, 0 }, { HDA_INTEL_LPTLP2, "Intel Lynx Point-LP", 0, 0 }, { HDA_INTEL_82801F, "Intel 82801F", 0, 0 }, { HDA_INTEL_63XXESB, "Intel 631x/632xESB", 0, 0 }, { HDA_INTEL_82801G, "Intel 82801G", 0, 0 }, { HDA_INTEL_82801H, "Intel 82801H", 0, 0 }, { HDA_INTEL_82801I, "Intel 82801I", 0, 0 }, { HDA_INTEL_82801JI, "Intel 82801JI", 0, 0 }, { HDA_INTEL_82801JD, "Intel 82801JD", 0, 0 }, { HDA_INTEL_PCH, "Intel 5 Series/3400 Series", 0, 0 }, { HDA_INTEL_PCH2, "Intel 5 Series/3400 Series", 0, 0 }, { HDA_INTEL_SCH, "Intel SCH", 0, 0 }, { HDA_NVIDIA_MCP51, "NVIDIA MCP51", 0, HDAC_QUIRK_MSI }, { HDA_NVIDIA_MCP55, "NVIDIA MCP55", 0, HDAC_QUIRK_MSI }, { HDA_NVIDIA_MCP61_1, "NVIDIA MCP61", 0, 0 }, { HDA_NVIDIA_MCP61_2, "NVIDIA MCP61", 0, 0 }, { HDA_NVIDIA_MCP65_1, "NVIDIA MCP65", 0, 0 }, { HDA_NVIDIA_MCP65_2, "NVIDIA MCP65", 0, 0 }, { HDA_NVIDIA_MCP67_1, "NVIDIA MCP67", 0, 0 }, { HDA_NVIDIA_MCP67_2, "NVIDIA MCP67", 0, 0 }, { HDA_NVIDIA_MCP73_1, "NVIDIA MCP73", 0, 0 }, { HDA_NVIDIA_MCP73_2, "NVIDIA MCP73", 0, 0 }, { HDA_NVIDIA_MCP78_1, "NVIDIA MCP78", 0, HDAC_QUIRK_64BIT }, { HDA_NVIDIA_MCP78_2, "NVIDIA MCP78", 0, HDAC_QUIRK_64BIT }, { HDA_NVIDIA_MCP78_3, "NVIDIA MCP78", 0, HDAC_QUIRK_64BIT }, { HDA_NVIDIA_MCP78_4, "NVIDIA MCP78", 0, HDAC_QUIRK_64BIT }, { HDA_NVIDIA_MCP79_1, "NVIDIA MCP79", 0, 0 }, { HDA_NVIDIA_MCP79_2, "NVIDIA MCP79", 0, 0 }, { HDA_NVIDIA_MCP79_3, "NVIDIA MCP79", 0, 0 }, { HDA_NVIDIA_MCP79_4, "NVIDIA MCP79", 0, 0 }, { HDA_NVIDIA_MCP89_1, "NVIDIA MCP89", 0, 0 }, { HDA_NVIDIA_MCP89_2, "NVIDIA MCP89", 0, 0 }, { HDA_NVIDIA_MCP89_3, "NVIDIA MCP89", 0, 0 }, { HDA_NVIDIA_MCP89_4, "NVIDIA MCP89", 0, 0 }, { HDA_NVIDIA_0BE2, "NVIDIA (0x0be2)", 0, HDAC_QUIRK_MSI }, { HDA_NVIDIA_0BE3, "NVIDIA (0x0be3)", 0, HDAC_QUIRK_MSI }, { HDA_NVIDIA_0BE4, "NVIDIA (0x0be4)", 0, HDAC_QUIRK_MSI }, { HDA_NVIDIA_GT100, "NVIDIA GT100", 0, HDAC_QUIRK_MSI }, { HDA_NVIDIA_GT104, "NVIDIA GT104", 0, HDAC_QUIRK_MSI }, { HDA_NVIDIA_GT106, "NVIDIA GT106", 0, HDAC_QUIRK_MSI }, { HDA_NVIDIA_GT108, "NVIDIA GT108", 0, HDAC_QUIRK_MSI }, { HDA_NVIDIA_GT116, "NVIDIA GT116", 0, HDAC_QUIRK_MSI }, { HDA_NVIDIA_GF119, "NVIDIA GF119", 0, 0 }, { HDA_NVIDIA_GF110_1, "NVIDIA GF110", 0, HDAC_QUIRK_MSI }, { HDA_NVIDIA_GF110_2, "NVIDIA GF110", 0, HDAC_QUIRK_MSI }, { HDA_ATI_SB450, "ATI SB450", 0, 0 }, { HDA_ATI_SB600, "ATI SB600", 0, 0 }, { HDA_ATI_RS600, "ATI RS600", 0, 0 }, { HDA_ATI_RS690, "ATI RS690", 0, 0 }, { HDA_ATI_RS780, "ATI RS780", 0, 0 }, { HDA_ATI_R600, "ATI R600", 0, 0 }, { HDA_ATI_RV610, "ATI RV610", 0, 0 }, { HDA_ATI_RV620, "ATI RV620", 0, 0 }, { HDA_ATI_RV630, "ATI RV630", 0, 0 }, { HDA_ATI_RV635, "ATI RV635", 0, 0 }, { HDA_ATI_RV710, "ATI RV710", 0, 0 }, { HDA_ATI_RV730, "ATI RV730", 0, 0 }, { HDA_ATI_RV740, "ATI RV740", 0, 0 }, { HDA_ATI_RV770, "ATI RV770", 0, 0 }, { HDA_ATI_RV810, "ATI RV810", 0, 0 }, { HDA_ATI_RV830, "ATI RV830", 0, 0 }, { HDA_ATI_RV840, "ATI RV840", 0, 0 }, { HDA_ATI_RV870, "ATI RV870", 0, 0 }, { HDA_ATI_RV910, "ATI RV910", 0, 0 }, { HDA_ATI_RV930, "ATI RV930", 0, 0 }, { HDA_ATI_RV940, "ATI RV940", 0, 0 }, { HDA_ATI_RV970, "ATI RV970", 0, 0 }, { HDA_ATI_R1000, "ATI R1000", 0, 0 }, { HDA_RDC_M3010, "RDC M3010", 0, 0 }, { HDA_VIA_VT82XX, "VIA VT8251/8237A",0, 0 }, { HDA_SIS_966, "SiS 966", 0, 0 }, { HDA_ULI_M5461, "ULI M5461", 0, 0 }, /* Unknown */ { HDA_INTEL_ALL, "Intel", 0, 0 }, { HDA_NVIDIA_ALL, "NVIDIA", 0, 0 }, { HDA_ATI_ALL, "ATI", 0, 0 }, { HDA_VIA_ALL, "VIA", 0, 0 }, { HDA_SIS_ALL, "SiS", 0, 0 }, { HDA_ULI_ALL, "ULI", 0, 0 }, }; static const struct { uint16_t vendor; uint8_t reg; uint8_t mask; uint8_t enable; } hdac_pcie_snoop[] = { { INTEL_VENDORID, 0x00, 0x00, 0x00 }, { ATI_VENDORID, 0x42, 0xf8, 0x02 }, { NVIDIA_VENDORID, 0x4e, 0xf0, 0x0f }, }; /**************************************************************************** * Function prototypes ****************************************************************************/ static void hdac_intr_handler(void *); static int hdac_reset(struct hdac_softc *, int); static int hdac_get_capabilities(struct hdac_softc *); static void hdac_dma_cb(void *, bus_dma_segment_t *, int, int); static int hdac_dma_alloc(struct hdac_softc *, struct hdac_dma *, bus_size_t); static void hdac_dma_free(struct hdac_softc *, struct hdac_dma *); static int hdac_mem_alloc(struct hdac_softc *); static void hdac_mem_free(struct hdac_softc *); static int hdac_irq_alloc(struct hdac_softc *); static void hdac_irq_free(struct hdac_softc *); static void hdac_corb_init(struct hdac_softc *); static void hdac_rirb_init(struct hdac_softc *); static void hdac_corb_start(struct hdac_softc *); static void hdac_rirb_start(struct hdac_softc *); static void hdac_attach2(void *); static uint32_t hdac_send_command(struct hdac_softc *, nid_t, uint32_t); static int hdac_probe(device_t); static int hdac_attach(device_t); static int hdac_detach(device_t); static int hdac_suspend(device_t); static int hdac_resume(device_t); static int hdac_rirb_flush(struct hdac_softc *sc); static int hdac_unsolq_flush(struct hdac_softc *sc); #define hdac_command(a1, a2, a3) \ hdac_send_command(a1, a3, a2) /* This function surely going to make its way into upper level someday. */ static void hdac_config_fetch(struct hdac_softc *sc, uint32_t *on, uint32_t *off) { const char *res = NULL; int i = 0, j, k, len, inv; if (resource_string_value(device_get_name(sc->dev), device_get_unit(sc->dev), "config", &res) != 0) return; if (!(res != NULL && strlen(res) > 0)) return; HDA_BOOTVERBOSE( device_printf(sc->dev, "Config options:"); ); for (;;) { while (res[i] != '\0' && (res[i] == ',' || isspace(res[i]) != 0)) i++; if (res[i] == '\0') { HDA_BOOTVERBOSE( printf("\n"); ); return; } j = i; while (res[j] != '\0' && !(res[j] == ',' || isspace(res[j]) != 0)) j++; len = j - i; if (len > 2 && strncmp(res + i, "no", 2) == 0) inv = 2; else inv = 0; for (k = 0; len > inv && k < nitems(hdac_quirks_tab); k++) { if (strncmp(res + i + inv, hdac_quirks_tab[k].key, len - inv) != 0) continue; if (len - inv != strlen(hdac_quirks_tab[k].key)) continue; HDA_BOOTVERBOSE( printf(" %s%s", (inv != 0) ? "no" : "", hdac_quirks_tab[k].key); ); if (inv == 0) { *on |= hdac_quirks_tab[k].value; *on &= ~hdac_quirks_tab[k].value; } else if (inv != 0) { *off |= hdac_quirks_tab[k].value; *off &= ~hdac_quirks_tab[k].value; } break; } i = j; } } /**************************************************************************** * void hdac_intr_handler(void *) * * Interrupt handler. Processes interrupts received from the hdac. ****************************************************************************/ static void hdac_intr_handler(void *context) { struct hdac_softc *sc; device_t dev; uint32_t intsts; uint8_t rirbsts; int i; sc = (struct hdac_softc *)context; hdac_lock(sc); /* Do we have anything to do? */ intsts = HDAC_READ_4(&sc->mem, HDAC_INTSTS); if ((intsts & HDAC_INTSTS_GIS) == 0) { hdac_unlock(sc); return; } /* Was this a controller interrupt? */ if (intsts & HDAC_INTSTS_CIS) { rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS); /* Get as many responses that we can */ while (rirbsts & HDAC_RIRBSTS_RINTFL) { HDAC_WRITE_1(&sc->mem, HDAC_RIRBSTS, HDAC_RIRBSTS_RINTFL); hdac_rirb_flush(sc); rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS); } if (sc->unsolq_rp != sc->unsolq_wp) taskqueue_enqueue(taskqueue_thread, &sc->unsolq_task); } if (intsts & HDAC_INTSTS_SIS_MASK) { for (i = 0; i < sc->num_ss; i++) { if ((intsts & (1 << i)) == 0) continue; HDAC_WRITE_1(&sc->mem, (i << 5) + HDAC_SDSTS, HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS ); if ((dev = sc->streams[i].dev) != NULL) { HDAC_STREAM_INTR(dev, sc->streams[i].dir, sc->streams[i].stream); } } } HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, intsts); hdac_unlock(sc); } static void hdac_poll_callback(void *arg) { struct hdac_softc *sc = arg; if (sc == NULL) return; hdac_lock(sc); if (sc->polling == 0) { hdac_unlock(sc); return; } callout_reset(&sc->poll_callout, sc->poll_ival, hdac_poll_callback, sc); hdac_unlock(sc); hdac_intr_handler(sc); } /**************************************************************************** * int hdac_reset(hdac_softc *, int) * * Reset the hdac to a quiescent and known state. ****************************************************************************/ static int hdac_reset(struct hdac_softc *sc, int wakeup) { uint32_t gctl; int count, i; /* * Stop all Streams DMA engine */ for (i = 0; i < sc->num_iss; i++) HDAC_WRITE_4(&sc->mem, HDAC_ISDCTL(sc, i), 0x0); for (i = 0; i < sc->num_oss; i++) HDAC_WRITE_4(&sc->mem, HDAC_OSDCTL(sc, i), 0x0); for (i = 0; i < sc->num_bss; i++) HDAC_WRITE_4(&sc->mem, HDAC_BSDCTL(sc, i), 0x0); /* * Stop Control DMA engines. */ HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, 0x0); HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, 0x0); /* * Reset DMA position buffer. */ HDAC_WRITE_4(&sc->mem, HDAC_DPIBLBASE, 0x0); HDAC_WRITE_4(&sc->mem, HDAC_DPIBUBASE, 0x0); /* * Reset the controller. The reset must remain asserted for * a minimum of 100us. */ gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL); HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl & ~HDAC_GCTL_CRST); count = 10000; do { gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL); if (!(gctl & HDAC_GCTL_CRST)) break; DELAY(10); } while (--count); if (gctl & HDAC_GCTL_CRST) { device_printf(sc->dev, "Unable to put hdac in reset\n"); return (ENXIO); } /* If wakeup is not requested - leave the controller in reset state. */ if (!wakeup) return (0); DELAY(100); gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL); HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl | HDAC_GCTL_CRST); count = 10000; do { gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL); if (gctl & HDAC_GCTL_CRST) break; DELAY(10); } while (--count); if (!(gctl & HDAC_GCTL_CRST)) { device_printf(sc->dev, "Device stuck in reset\n"); return (ENXIO); } /* * Wait for codecs to finish their own reset sequence. The delay here * should be of 250us but for some reasons, on it's not enough on my * computer. Let's use twice as much as necessary to make sure that * it's reset properly. */ DELAY(1000); return (0); } /**************************************************************************** * int hdac_get_capabilities(struct hdac_softc *); * * Retreive the general capabilities of the hdac; * Number of Input Streams * Number of Output Streams * Number of bidirectional Streams * 64bit ready * CORB and RIRB sizes ****************************************************************************/ static int hdac_get_capabilities(struct hdac_softc *sc) { uint16_t gcap; uint8_t corbsize, rirbsize; gcap = HDAC_READ_2(&sc->mem, HDAC_GCAP); sc->num_iss = HDAC_GCAP_ISS(gcap); sc->num_oss = HDAC_GCAP_OSS(gcap); sc->num_bss = HDAC_GCAP_BSS(gcap); sc->num_ss = sc->num_iss + sc->num_oss + sc->num_bss; sc->num_sdo = HDAC_GCAP_NSDO(gcap); sc->support_64bit = (gcap & HDAC_GCAP_64OK) != 0; if (sc->quirks_on & HDAC_QUIRK_64BIT) sc->support_64bit = 1; else if (sc->quirks_off & HDAC_QUIRK_64BIT) sc->support_64bit = 0; corbsize = HDAC_READ_1(&sc->mem, HDAC_CORBSIZE); if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_256) == HDAC_CORBSIZE_CORBSZCAP_256) sc->corb_size = 256; else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_16) == HDAC_CORBSIZE_CORBSZCAP_16) sc->corb_size = 16; else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_2) == HDAC_CORBSIZE_CORBSZCAP_2) sc->corb_size = 2; else { device_printf(sc->dev, "%s: Invalid corb size (%x)\n", __func__, corbsize); return (ENXIO); } rirbsize = HDAC_READ_1(&sc->mem, HDAC_RIRBSIZE); if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_256) == HDAC_RIRBSIZE_RIRBSZCAP_256) sc->rirb_size = 256; else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_16) == HDAC_RIRBSIZE_RIRBSZCAP_16) sc->rirb_size = 16; else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_2) == HDAC_RIRBSIZE_RIRBSZCAP_2) sc->rirb_size = 2; else { device_printf(sc->dev, "%s: Invalid rirb size (%x)\n", __func__, rirbsize); return (ENXIO); } HDA_BOOTVERBOSE( device_printf(sc->dev, "Caps: OSS %d, ISS %d, BSS %d, " "NSDO %d%s, CORB %d, RIRB %d\n", sc->num_oss, sc->num_iss, sc->num_bss, 1 << sc->num_sdo, sc->support_64bit ? ", 64bit" : "", sc->corb_size, sc->rirb_size); ); return (0); } /**************************************************************************** * void hdac_dma_cb * * This function is called by bus_dmamap_load when the mapping has been * established. We just record the physical address of the mapping into * the struct hdac_dma passed in. ****************************************************************************/ static void hdac_dma_cb(void *callback_arg, bus_dma_segment_t *segs, int nseg, int error) { struct hdac_dma *dma; if (error == 0) { dma = (struct hdac_dma *)callback_arg; dma->dma_paddr = segs[0].ds_addr; } } /**************************************************************************** * int hdac_dma_alloc * * This function allocate and setup a dma region (struct hdac_dma). * It must be freed by a corresponding hdac_dma_free. ****************************************************************************/ static int hdac_dma_alloc(struct hdac_softc *sc, struct hdac_dma *dma, bus_size_t size) { bus_size_t roundsz; int result; roundsz = roundup2(size, HDA_DMA_ALIGNMENT); bzero(dma, sizeof(*dma)); /* * Create a DMA tag */ result = bus_dma_tag_create( bus_get_dma_tag(sc->dev), /* parent */ HDA_DMA_ALIGNMENT, /* alignment */ 0, /* boundary */ (sc->support_64bit) ? BUS_SPACE_MAXADDR : BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, /* filtfunc */ NULL, /* fistfuncarg */ roundsz, /* maxsize */ 1, /* nsegments */ roundsz, /* maxsegsz */ 0, /* flags */ NULL, /* lockfunc */ NULL, /* lockfuncarg */ &dma->dma_tag); /* dmat */ if (result != 0) { device_printf(sc->dev, "%s: bus_dma_tag_create failed (%x)\n", __func__, result); goto hdac_dma_alloc_fail; } /* * Allocate DMA memory */ result = bus_dmamem_alloc(dma->dma_tag, (void **)&dma->dma_vaddr, BUS_DMA_NOWAIT | BUS_DMA_ZERO | ((sc->flags & HDAC_F_DMA_NOCACHE) ? BUS_DMA_NOCACHE : 0), &dma->dma_map); if (result != 0) { device_printf(sc->dev, "%s: bus_dmamem_alloc failed (%x)\n", __func__, result); goto hdac_dma_alloc_fail; } dma->dma_size = roundsz; /* * Map the memory */ result = bus_dmamap_load(dma->dma_tag, dma->dma_map, (void *)dma->dma_vaddr, roundsz, hdac_dma_cb, (void *)dma, 0); if (result != 0 || dma->dma_paddr == 0) { if (result == 0) result = ENOMEM; device_printf(sc->dev, "%s: bus_dmamem_load failed (%x)\n", __func__, result); goto hdac_dma_alloc_fail; } HDA_BOOTHVERBOSE( device_printf(sc->dev, "%s: size=%ju -> roundsz=%ju\n", __func__, (uintmax_t)size, (uintmax_t)roundsz); ); return (0); hdac_dma_alloc_fail: hdac_dma_free(sc, dma); return (result); } /**************************************************************************** * void hdac_dma_free(struct hdac_softc *, struct hdac_dma *) * * Free a struct dhac_dma that has been previously allocated via the * hdac_dma_alloc function. ****************************************************************************/ static void hdac_dma_free(struct hdac_softc *sc, struct hdac_dma *dma) { if (dma->dma_paddr != 0) { #if 0 /* Flush caches */ bus_dmamap_sync(dma->dma_tag, dma->dma_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); #endif bus_dmamap_unload(dma->dma_tag, dma->dma_map); dma->dma_paddr = 0; } if (dma->dma_vaddr != NULL) { bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map); dma->dma_vaddr = NULL; } if (dma->dma_tag != NULL) { bus_dma_tag_destroy(dma->dma_tag); dma->dma_tag = NULL; } dma->dma_size = 0; } /**************************************************************************** * int hdac_mem_alloc(struct hdac_softc *) * * Allocate all the bus resources necessary to speak with the physical * controller. ****************************************************************************/ static int hdac_mem_alloc(struct hdac_softc *sc) { struct hdac_mem *mem; mem = &sc->mem; mem->mem_rid = PCIR_BAR(0); mem->mem_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, &mem->mem_rid, RF_ACTIVE); if (mem->mem_res == NULL) { device_printf(sc->dev, "%s: Unable to allocate memory resource\n", __func__); return (ENOMEM); } mem->mem_tag = rman_get_bustag(mem->mem_res); mem->mem_handle = rman_get_bushandle(mem->mem_res); return (0); } /**************************************************************************** * void hdac_mem_free(struct hdac_softc *) * * Free up resources previously allocated by hdac_mem_alloc. ****************************************************************************/ static void hdac_mem_free(struct hdac_softc *sc) { struct hdac_mem *mem; mem = &sc->mem; if (mem->mem_res != NULL) bus_release_resource(sc->dev, SYS_RES_MEMORY, mem->mem_rid, mem->mem_res); mem->mem_res = NULL; } /**************************************************************************** * int hdac_irq_alloc(struct hdac_softc *) * * Allocate and setup the resources necessary for interrupt handling. ****************************************************************************/ static int hdac_irq_alloc(struct hdac_softc *sc) { struct hdac_irq *irq; int result; irq = &sc->irq; irq->irq_rid = 0x0; if ((sc->quirks_off & HDAC_QUIRK_MSI) == 0 && (result = pci_msi_count(sc->dev)) == 1 && pci_alloc_msi(sc->dev, &result) == 0) irq->irq_rid = 0x1; irq->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->irq_rid, RF_SHAREABLE | RF_ACTIVE); if (irq->irq_res == NULL) { device_printf(sc->dev, "%s: Unable to allocate irq\n", __func__); goto hdac_irq_alloc_fail; } result = bus_setup_intr(sc->dev, irq->irq_res, INTR_MPSAFE | INTR_TYPE_AV, NULL, hdac_intr_handler, sc, &irq->irq_handle); if (result != 0) { device_printf(sc->dev, "%s: Unable to setup interrupt handler (%x)\n", __func__, result); goto hdac_irq_alloc_fail; } return (0); hdac_irq_alloc_fail: hdac_irq_free(sc); return (ENXIO); } /**************************************************************************** * void hdac_irq_free(struct hdac_softc *) * * Free up resources previously allocated by hdac_irq_alloc. ****************************************************************************/ static void hdac_irq_free(struct hdac_softc *sc) { struct hdac_irq *irq; irq = &sc->irq; if (irq->irq_res != NULL && irq->irq_handle != NULL) bus_teardown_intr(sc->dev, irq->irq_res, irq->irq_handle); if (irq->irq_res != NULL) bus_release_resource(sc->dev, SYS_RES_IRQ, irq->irq_rid, irq->irq_res); if (irq->irq_rid == 0x1) pci_release_msi(sc->dev); irq->irq_handle = NULL; irq->irq_res = NULL; irq->irq_rid = 0x0; } /**************************************************************************** * void hdac_corb_init(struct hdac_softc *) * * Initialize the corb registers for operations but do not start it up yet. * The CORB engine must not be running when this function is called. ****************************************************************************/ static void hdac_corb_init(struct hdac_softc *sc) { uint8_t corbsize; uint64_t corbpaddr; /* Setup the CORB size. */ switch (sc->corb_size) { case 256: corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_256); break; case 16: corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_16); break; case 2: corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_2); break; default: panic("%s: Invalid CORB size (%x)\n", __func__, sc->corb_size); } HDAC_WRITE_1(&sc->mem, HDAC_CORBSIZE, corbsize); /* Setup the CORB Address in the hdac */ corbpaddr = (uint64_t)sc->corb_dma.dma_paddr; HDAC_WRITE_4(&sc->mem, HDAC_CORBLBASE, (uint32_t)corbpaddr); HDAC_WRITE_4(&sc->mem, HDAC_CORBUBASE, (uint32_t)(corbpaddr >> 32)); /* Set the WP and RP */ sc->corb_wp = 0; HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp); HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, HDAC_CORBRP_CORBRPRST); /* * The HDA specification indicates that the CORBRPRST bit will always * read as zero. Unfortunately, it seems that at least the 82801G * doesn't reset the bit to zero, which stalls the corb engine. * manually reset the bit to zero before continuing. */ HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, 0x0); /* Enable CORB error reporting */ #if 0 HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, HDAC_CORBCTL_CMEIE); #endif } /**************************************************************************** * void hdac_rirb_init(struct hdac_softc *) * * Initialize the rirb registers for operations but do not start it up yet. * The RIRB engine must not be running when this function is called. ****************************************************************************/ static void hdac_rirb_init(struct hdac_softc *sc) { uint8_t rirbsize; uint64_t rirbpaddr; /* Setup the RIRB size. */ switch (sc->rirb_size) { case 256: rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_256); break; case 16: rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_16); break; case 2: rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_2); break; default: panic("%s: Invalid RIRB size (%x)\n", __func__, sc->rirb_size); } HDAC_WRITE_1(&sc->mem, HDAC_RIRBSIZE, rirbsize); /* Setup the RIRB Address in the hdac */ rirbpaddr = (uint64_t)sc->rirb_dma.dma_paddr; HDAC_WRITE_4(&sc->mem, HDAC_RIRBLBASE, (uint32_t)rirbpaddr); HDAC_WRITE_4(&sc->mem, HDAC_RIRBUBASE, (uint32_t)(rirbpaddr >> 32)); /* Setup the WP and RP */ sc->rirb_rp = 0; HDAC_WRITE_2(&sc->mem, HDAC_RIRBWP, HDAC_RIRBWP_RIRBWPRST); /* Setup the interrupt threshold */ HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, sc->rirb_size / 2); /* Enable Overrun and response received reporting */ #if 0 HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, HDAC_RIRBCTL_RIRBOIC | HDAC_RIRBCTL_RINTCTL); #else HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, HDAC_RIRBCTL_RINTCTL); #endif #if 0 /* * Make sure that the Host CPU cache doesn't contain any dirty * cache lines that falls in the rirb. If I understood correctly, it * should be sufficient to do this only once as the rirb is purely * read-only from now on. */ bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map, BUS_DMASYNC_PREREAD); #endif } /**************************************************************************** * void hdac_corb_start(hdac_softc *) * * Startup the corb DMA engine ****************************************************************************/ static void hdac_corb_start(struct hdac_softc *sc) { uint32_t corbctl; corbctl = HDAC_READ_1(&sc->mem, HDAC_CORBCTL); corbctl |= HDAC_CORBCTL_CORBRUN; HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, corbctl); } /**************************************************************************** * void hdac_rirb_start(hdac_softc *) * * Startup the rirb DMA engine ****************************************************************************/ static void hdac_rirb_start(struct hdac_softc *sc) { uint32_t rirbctl; rirbctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL); rirbctl |= HDAC_RIRBCTL_RIRBDMAEN; HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, rirbctl); } static int hdac_rirb_flush(struct hdac_softc *sc) { struct hdac_rirb *rirb_base, *rirb; nid_t cad; uint32_t resp; uint8_t rirbwp; int ret; rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr; rirbwp = HDAC_READ_1(&sc->mem, HDAC_RIRBWP); #if 0 bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map, BUS_DMASYNC_POSTREAD); #endif ret = 0; while (sc->rirb_rp != rirbwp) { sc->rirb_rp++; sc->rirb_rp %= sc->rirb_size; rirb = &rirb_base[sc->rirb_rp]; cad = HDAC_RIRB_RESPONSE_EX_SDATA_IN(rirb->response_ex); resp = rirb->response; if (rirb->response_ex & HDAC_RIRB_RESPONSE_EX_UNSOLICITED) { sc->unsolq[sc->unsolq_wp++] = resp; sc->unsolq_wp %= HDAC_UNSOLQ_MAX; sc->unsolq[sc->unsolq_wp++] = cad; sc->unsolq_wp %= HDAC_UNSOLQ_MAX; } else if (sc->codecs[cad].pending <= 0) { device_printf(sc->dev, "Unexpected unsolicited " "response from address %d: %08x\n", cad, resp); } else { sc->codecs[cad].response = resp; sc->codecs[cad].pending--; } ret++; } return (ret); } static int hdac_unsolq_flush(struct hdac_softc *sc) { device_t child; nid_t cad; uint32_t resp; int ret = 0; if (sc->unsolq_st == HDAC_UNSOLQ_READY) { sc->unsolq_st = HDAC_UNSOLQ_BUSY; while (sc->unsolq_rp != sc->unsolq_wp) { resp = sc->unsolq[sc->unsolq_rp++]; sc->unsolq_rp %= HDAC_UNSOLQ_MAX; cad = sc->unsolq[sc->unsolq_rp++]; sc->unsolq_rp %= HDAC_UNSOLQ_MAX; if ((child = sc->codecs[cad].dev) != NULL) HDAC_UNSOL_INTR(child, resp); ret++; } sc->unsolq_st = HDAC_UNSOLQ_READY; } return (ret); } /**************************************************************************** * uint32_t hdac_command_sendone_internal * * Wrapper function that sends only one command to a given codec ****************************************************************************/ static uint32_t hdac_send_command(struct hdac_softc *sc, nid_t cad, uint32_t verb) { int timeout; uint32_t *corb; if (!hdac_lockowned(sc)) device_printf(sc->dev, "WARNING!!!! mtx not owned!!!!\n"); verb &= ~HDA_CMD_CAD_MASK; verb |= ((uint32_t)cad) << HDA_CMD_CAD_SHIFT; sc->codecs[cad].response = HDA_INVALID; sc->codecs[cad].pending++; sc->corb_wp++; sc->corb_wp %= sc->corb_size; corb = (uint32_t *)sc->corb_dma.dma_vaddr; #if 0 bus_dmamap_sync(sc->corb_dma.dma_tag, sc->corb_dma.dma_map, BUS_DMASYNC_PREWRITE); #endif corb[sc->corb_wp] = verb; #if 0 bus_dmamap_sync(sc->corb_dma.dma_tag, sc->corb_dma.dma_map, BUS_DMASYNC_POSTWRITE); #endif HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp); timeout = 10000; do { if (hdac_rirb_flush(sc) == 0) DELAY(10); } while (sc->codecs[cad].pending != 0 && --timeout); if (sc->codecs[cad].pending != 0) { device_printf(sc->dev, "Command timeout on address %d\n", cad); sc->codecs[cad].pending = 0; } if (sc->unsolq_rp != sc->unsolq_wp) taskqueue_enqueue(taskqueue_thread, &sc->unsolq_task); return (sc->codecs[cad].response); } /**************************************************************************** * Device Methods ****************************************************************************/ /**************************************************************************** * int hdac_probe(device_t) * * Probe for the presence of an hdac. If none is found, check for a generic * match using the subclass of the device. ****************************************************************************/ static int hdac_probe(device_t dev) { int i, result; uint32_t model; uint16_t class, subclass; char desc[64]; model = (uint32_t)pci_get_device(dev) << 16; model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff; class = pci_get_class(dev); subclass = pci_get_subclass(dev); bzero(desc, sizeof(desc)); result = ENXIO; for (i = 0; i < nitems(hdac_devices); i++) { if (hdac_devices[i].model == model) { strlcpy(desc, hdac_devices[i].desc, sizeof(desc)); result = BUS_PROBE_DEFAULT; break; } if (HDA_DEV_MATCH(hdac_devices[i].model, model) && class == PCIC_MULTIMEDIA && subclass == PCIS_MULTIMEDIA_HDA) { snprintf(desc, sizeof(desc), "%s (0x%04x)", hdac_devices[i].desc, pci_get_device(dev)); result = BUS_PROBE_GENERIC; break; } } if (result == ENXIO && class == PCIC_MULTIMEDIA && subclass == PCIS_MULTIMEDIA_HDA) { snprintf(desc, sizeof(desc), "Generic (0x%08x)", model); result = BUS_PROBE_GENERIC; } if (result != ENXIO) { strlcat(desc, " HDA Controller", sizeof(desc)); device_set_desc_copy(dev, desc); } return (result); } static void hdac_unsolq_task(void *context, int pending) { struct hdac_softc *sc; sc = (struct hdac_softc *)context; hdac_lock(sc); hdac_unsolq_flush(sc); hdac_unlock(sc); } /**************************************************************************** * int hdac_attach(device_t) * * Attach the device into the kernel. Interrupts usually won't be enabled * when this function is called. Setup everything that doesn't require * interrupts and defer probing of codecs until interrupts are enabled. ****************************************************************************/ static int hdac_attach(device_t dev) { struct hdac_softc *sc; int result; int i, devid = -1; uint32_t model; uint16_t class, subclass; uint16_t vendor; uint8_t v; sc = device_get_softc(dev); HDA_BOOTVERBOSE( device_printf(dev, "PCI card vendor: 0x%04x, device: 0x%04x\n", pci_get_subvendor(dev), pci_get_subdevice(dev)); device_printf(dev, "HDA Driver Revision: %s\n", HDA_DRV_TEST_REV); ); model = (uint32_t)pci_get_device(dev) << 16; model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff; class = pci_get_class(dev); subclass = pci_get_subclass(dev); for (i = 0; i < nitems(hdac_devices); i++) { if (hdac_devices[i].model == model) { devid = i; break; } if (HDA_DEV_MATCH(hdac_devices[i].model, model) && class == PCIC_MULTIMEDIA && subclass == PCIS_MULTIMEDIA_HDA) { devid = i; break; } } sc->lock = snd_mtxcreate(device_get_nameunit(dev), "HDA driver mutex"); sc->dev = dev; TASK_INIT(&sc->unsolq_task, 0, hdac_unsolq_task, sc); callout_init(&sc->poll_callout, CALLOUT_MPSAFE); for (i = 0; i < HDAC_CODEC_MAX; i++) sc->codecs[i].dev = NULL; if (devid >= 0) { sc->quirks_on = hdac_devices[devid].quirks_on; sc->quirks_off = hdac_devices[devid].quirks_off; } else { sc->quirks_on = 0; sc->quirks_off = 0; } if (resource_int_value(device_get_name(dev), device_get_unit(dev), "msi", &i) == 0) { if (i == 0) sc->quirks_off |= HDAC_QUIRK_MSI; else { sc->quirks_on |= HDAC_QUIRK_MSI; sc->quirks_off |= ~HDAC_QUIRK_MSI; } } hdac_config_fetch(sc, &sc->quirks_on, &sc->quirks_off); HDA_BOOTVERBOSE( device_printf(sc->dev, "Config options: on=0x%08x off=0x%08x\n", sc->quirks_on, sc->quirks_off); ); sc->poll_ival = hz; if (resource_int_value(device_get_name(dev), device_get_unit(dev), "polling", &i) == 0 && i != 0) sc->polling = 1; else sc->polling = 0; pci_enable_busmaster(dev); vendor = pci_get_vendor(dev); if (vendor == INTEL_VENDORID) { /* TCSEL -> TC0 */ v = pci_read_config(dev, 0x44, 1); pci_write_config(dev, 0x44, v & 0xf8, 1); HDA_BOOTHVERBOSE( device_printf(dev, "TCSEL: 0x%02d -> 0x%02d\n", v, pci_read_config(dev, 0x44, 1)); ); } #if defined(__i386__) || defined(__amd64__) sc->flags |= HDAC_F_DMA_NOCACHE; if (resource_int_value(device_get_name(dev), device_get_unit(dev), "snoop", &i) == 0 && i != 0) { #else sc->flags &= ~HDAC_F_DMA_NOCACHE; #endif /* * Try to enable PCIe snoop to avoid messing around with * uncacheable DMA attribute. Since PCIe snoop register * config is pretty much vendor specific, there are no * general solutions on how to enable it, forcing us (even * Microsoft) to enable uncacheable or write combined DMA * by default. * * http://msdn2.microsoft.com/en-us/library/ms790324.aspx */ for (i = 0; i < nitems(hdac_pcie_snoop); i++) { if (hdac_pcie_snoop[i].vendor != vendor) continue; sc->flags &= ~HDAC_F_DMA_NOCACHE; if (hdac_pcie_snoop[i].reg == 0x00) break; v = pci_read_config(dev, hdac_pcie_snoop[i].reg, 1); if ((v & hdac_pcie_snoop[i].enable) == hdac_pcie_snoop[i].enable) break; v &= hdac_pcie_snoop[i].mask; v |= hdac_pcie_snoop[i].enable; pci_write_config(dev, hdac_pcie_snoop[i].reg, v, 1); v = pci_read_config(dev, hdac_pcie_snoop[i].reg, 1); if ((v & hdac_pcie_snoop[i].enable) != hdac_pcie_snoop[i].enable) { HDA_BOOTVERBOSE( device_printf(dev, "WARNING: Failed to enable PCIe " "snoop!\n"); ); #if defined(__i386__) || defined(__amd64__) sc->flags |= HDAC_F_DMA_NOCACHE; #endif } break; } #if defined(__i386__) || defined(__amd64__) } #endif HDA_BOOTHVERBOSE( device_printf(dev, "DMA Coherency: %s / vendor=0x%04x\n", (sc->flags & HDAC_F_DMA_NOCACHE) ? "Uncacheable" : "PCIe snoop", vendor); ); /* Allocate resources */ result = hdac_mem_alloc(sc); if (result != 0) goto hdac_attach_fail; result = hdac_irq_alloc(sc); if (result != 0) goto hdac_attach_fail; /* Get Capabilities */ result = hdac_get_capabilities(sc); if (result != 0) goto hdac_attach_fail; /* Allocate CORB, RIRB, POS and BDLs dma memory */ result = hdac_dma_alloc(sc, &sc->corb_dma, sc->corb_size * sizeof(uint32_t)); if (result != 0) goto hdac_attach_fail; result = hdac_dma_alloc(sc, &sc->rirb_dma, sc->rirb_size * sizeof(struct hdac_rirb)); if (result != 0) goto hdac_attach_fail; sc->streams = malloc(sizeof(struct hdac_stream) * sc->num_ss, M_HDAC, M_ZERO | M_WAITOK); for (i = 0; i < sc->num_ss; i++) { result = hdac_dma_alloc(sc, &sc->streams[i].bdl, sizeof(struct hdac_bdle) * HDA_BDL_MAX); if (result != 0) goto hdac_attach_fail; } if (sc->quirks_on & HDAC_QUIRK_DMAPOS) { if (hdac_dma_alloc(sc, &sc->pos_dma, (sc->num_ss) * 8) != 0) { HDA_BOOTVERBOSE( device_printf(dev, "Failed to " "allocate DMA pos buffer " "(non-fatal)\n"); ); } else { uint64_t addr = sc->pos_dma.dma_paddr; HDAC_WRITE_4(&sc->mem, HDAC_DPIBUBASE, addr >> 32); HDAC_WRITE_4(&sc->mem, HDAC_DPIBLBASE, (addr & HDAC_DPLBASE_DPLBASE_MASK) | HDAC_DPLBASE_DPLBASE_DMAPBE); } } result = bus_dma_tag_create( bus_get_dma_tag(sc->dev), /* parent */ HDA_DMA_ALIGNMENT, /* alignment */ 0, /* boundary */ (sc->support_64bit) ? BUS_SPACE_MAXADDR : BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, /* filtfunc */ NULL, /* fistfuncarg */ HDA_BUFSZ_MAX, /* maxsize */ 1, /* nsegments */ HDA_BUFSZ_MAX, /* maxsegsz */ 0, /* flags */ NULL, /* lockfunc */ NULL, /* lockfuncarg */ &sc->chan_dmat); /* dmat */ if (result != 0) { device_printf(dev, "%s: bus_dma_tag_create failed (%x)\n", __func__, result); goto hdac_attach_fail; } /* Quiesce everything */ HDA_BOOTHVERBOSE( device_printf(dev, "Reset controller...\n"); ); hdac_reset(sc, 1); /* Initialize the CORB and RIRB */ hdac_corb_init(sc); hdac_rirb_init(sc); /* Defer remaining of initialization until interrupts are enabled */ sc->intrhook.ich_func = hdac_attach2; sc->intrhook.ich_arg = (void *)sc; if (cold == 0 || config_intrhook_establish(&sc->intrhook) != 0) { sc->intrhook.ich_func = NULL; hdac_attach2((void *)sc); } return (0); hdac_attach_fail: hdac_irq_free(sc); for (i = 0; i < sc->num_ss; i++) hdac_dma_free(sc, &sc->streams[i].bdl); free(sc->streams, M_HDAC); hdac_dma_free(sc, &sc->rirb_dma); hdac_dma_free(sc, &sc->corb_dma); hdac_mem_free(sc); snd_mtxfree(sc->lock); return (ENXIO); } static int sysctl_hdac_pindump(SYSCTL_HANDLER_ARGS) { struct hdac_softc *sc; device_t *devlist; device_t dev; int devcount, i, err, val; dev = oidp->oid_arg1; sc = device_get_softc(dev); if (sc == NULL) return (EINVAL); val = 0; err = sysctl_handle_int(oidp, &val, 0, req); if (err != 0 || req->newptr == NULL || val == 0) return (err); /* XXX: Temporary. For debugging. */ if (val == 100) { hdac_suspend(dev); return (0); } else if (val == 101) { hdac_resume(dev); return (0); } if ((err = device_get_children(dev, &devlist, &devcount)) != 0) return (err); hdac_lock(sc); for (i = 0; i < devcount; i++) HDAC_PINDUMP(devlist[i]); hdac_unlock(sc); free(devlist, M_TEMP); return (0); } static int hdac_mdata_rate(uint16_t fmt) { static const int mbits[8] = { 8, 16, 32, 32, 32, 32, 32, 32 }; int rate, bits; if (fmt & (1 << 14)) rate = 44100; else rate = 48000; rate *= ((fmt >> 11) & 0x07) + 1; rate /= ((fmt >> 8) & 0x07) + 1; bits = mbits[(fmt >> 4) & 0x03]; bits *= (fmt & 0x0f) + 1; return (rate * bits); } static int hdac_bdata_rate(uint16_t fmt, int output) { static const int bbits[8] = { 8, 16, 20, 24, 32, 32, 32, 32 }; int rate, bits; rate = 48000; rate *= ((fmt >> 11) & 0x07) + 1; bits = bbits[(fmt >> 4) & 0x03]; bits *= (fmt & 0x0f) + 1; if (!output) bits = ((bits + 7) & ~0x07) + 10; return (rate * bits); } static void hdac_poll_reinit(struct hdac_softc *sc) { int i, pollticks, min = 1000000; struct hdac_stream *s; if (sc->polling == 0) return; if (sc->unsol_registered > 0) min = hz / 2; for (i = 0; i < sc->num_ss; i++) { s = &sc->streams[i]; if (s->running == 0) continue; pollticks = ((uint64_t)hz * s->blksz) / (hdac_mdata_rate(s->format) / 8); pollticks >>= 1; if (pollticks > hz) pollticks = hz; if (pollticks < 1) { HDA_BOOTVERBOSE( device_printf(sc->dev, "poll interval < 1 tick !\n"); ); pollticks = 1; } if (min > pollticks) min = pollticks; } HDA_BOOTVERBOSE( device_printf(sc->dev, "poll interval %d -> %d ticks\n", sc->poll_ival, min); ); sc->poll_ival = min; if (min == 1000000) callout_stop(&sc->poll_callout); else callout_reset(&sc->poll_callout, 1, hdac_poll_callback, sc); } static int sysctl_hdac_polling(SYSCTL_HANDLER_ARGS) { struct hdac_softc *sc; device_t dev; uint32_t ctl; int err, val; dev = oidp->oid_arg1; sc = device_get_softc(dev); if (sc == NULL) return (EINVAL); hdac_lock(sc); val = sc->polling; hdac_unlock(sc); err = sysctl_handle_int(oidp, &val, 0, req); if (err != 0 || req->newptr == NULL) return (err); if (val < 0 || val > 1) return (EINVAL); hdac_lock(sc); if (val != sc->polling) { if (val == 0) { callout_stop(&sc->poll_callout); hdac_unlock(sc); callout_drain(&sc->poll_callout); hdac_lock(sc); sc->polling = 0; ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL); ctl |= HDAC_INTCTL_GIE; HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl); } else { ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL); ctl &= ~HDAC_INTCTL_GIE; HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl); sc->polling = 1; hdac_poll_reinit(sc); } } hdac_unlock(sc); return (err); } static void hdac_attach2(void *arg) { struct hdac_softc *sc; device_t child; uint32_t vendorid, revisionid; int i; uint16_t statests; sc = (struct hdac_softc *)arg; hdac_lock(sc); /* Remove ourselves from the config hooks */ if (sc->intrhook.ich_func != NULL) { config_intrhook_disestablish(&sc->intrhook); sc->intrhook.ich_func = NULL; } HDA_BOOTHVERBOSE( device_printf(sc->dev, "Starting CORB Engine...\n"); ); hdac_corb_start(sc); HDA_BOOTHVERBOSE( device_printf(sc->dev, "Starting RIRB Engine...\n"); ); hdac_rirb_start(sc); HDA_BOOTHVERBOSE( device_printf(sc->dev, "Enabling controller interrupt...\n"); ); HDAC_WRITE_4(&sc->mem, HDAC_GCTL, HDAC_READ_4(&sc->mem, HDAC_GCTL) | HDAC_GCTL_UNSOL); if (sc->polling == 0) { HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, HDAC_INTCTL_CIE | HDAC_INTCTL_GIE); } DELAY(1000); HDA_BOOTHVERBOSE( device_printf(sc->dev, "Scanning HDA codecs ...\n"); ); statests = HDAC_READ_2(&sc->mem, HDAC_STATESTS); hdac_unlock(sc); for (i = 0; i < HDAC_CODEC_MAX; i++) { if (HDAC_STATESTS_SDIWAKE(statests, i)) { HDA_BOOTHVERBOSE( device_printf(sc->dev, "Found CODEC at address %d\n", i); ); hdac_lock(sc); vendorid = hdac_send_command(sc, i, HDA_CMD_GET_PARAMETER(0, 0x0, HDA_PARAM_VENDOR_ID)); revisionid = hdac_send_command(sc, i, HDA_CMD_GET_PARAMETER(0, 0x0, HDA_PARAM_REVISION_ID)); hdac_unlock(sc); if (vendorid == HDA_INVALID && revisionid == HDA_INVALID) { device_printf(sc->dev, "CODEC is not responding!\n"); continue; } sc->codecs[i].vendor_id = HDA_PARAM_VENDOR_ID_VENDOR_ID(vendorid); sc->codecs[i].device_id = HDA_PARAM_VENDOR_ID_DEVICE_ID(vendorid); sc->codecs[i].revision_id = HDA_PARAM_REVISION_ID_REVISION_ID(revisionid); sc->codecs[i].stepping_id = HDA_PARAM_REVISION_ID_STEPPING_ID(revisionid); child = device_add_child(sc->dev, "hdacc", -1); if (child == NULL) { device_printf(sc->dev, "Failed to add CODEC device\n"); continue; } device_set_ivars(child, (void *)(intptr_t)i); sc->codecs[i].dev = child; } } bus_generic_attach(sc->dev); SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev), SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, "pindump", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev), sysctl_hdac_pindump, "I", "Dump pin states/data"); SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev), SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, "polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev), sysctl_hdac_polling, "I", "Enable polling mode"); } /**************************************************************************** * int hdac_suspend(device_t) * * Suspend and power down HDA bus and codecs. ****************************************************************************/ static int hdac_suspend(device_t dev) { struct hdac_softc *sc = device_get_softc(dev); HDA_BOOTHVERBOSE( device_printf(dev, "Suspend...\n"); ); bus_generic_suspend(dev); hdac_lock(sc); HDA_BOOTHVERBOSE( device_printf(dev, "Reset controller...\n"); ); callout_stop(&sc->poll_callout); hdac_reset(sc, 0); hdac_unlock(sc); callout_drain(&sc->poll_callout); taskqueue_drain(taskqueue_thread, &sc->unsolq_task); HDA_BOOTHVERBOSE( device_printf(dev, "Suspend done\n"); ); return (0); } /**************************************************************************** * int hdac_resume(device_t) * * Powerup and restore HDA bus and codecs state. ****************************************************************************/ static int hdac_resume(device_t dev) { struct hdac_softc *sc = device_get_softc(dev); int error; HDA_BOOTHVERBOSE( device_printf(dev, "Resume...\n"); ); hdac_lock(sc); /* Quiesce everything */ HDA_BOOTHVERBOSE( device_printf(dev, "Reset controller...\n"); ); hdac_reset(sc, 1); /* Initialize the CORB and RIRB */ hdac_corb_init(sc); hdac_rirb_init(sc); HDA_BOOTHVERBOSE( device_printf(dev, "Starting CORB Engine...\n"); ); hdac_corb_start(sc); HDA_BOOTHVERBOSE( device_printf(dev, "Starting RIRB Engine...\n"); ); hdac_rirb_start(sc); HDA_BOOTHVERBOSE( device_printf(dev, "Enabling controller interrupt...\n"); ); HDAC_WRITE_4(&sc->mem, HDAC_GCTL, HDAC_READ_4(&sc->mem, HDAC_GCTL) | HDAC_GCTL_UNSOL); HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, HDAC_INTCTL_CIE | HDAC_INTCTL_GIE); DELAY(1000); hdac_poll_reinit(sc); hdac_unlock(sc); error = bus_generic_resume(dev); HDA_BOOTHVERBOSE( device_printf(dev, "Resume done\n"); ); return (error); } /**************************************************************************** * int hdac_detach(device_t) * * Detach and free up resources utilized by the hdac device. ****************************************************************************/ static int hdac_detach(device_t dev) { struct hdac_softc *sc = device_get_softc(dev); device_t *devlist; int cad, i, devcount, error; if ((error = device_get_children(dev, &devlist, &devcount)) != 0) return (error); for (i = 0; i < devcount; i++) { cad = (intptr_t)device_get_ivars(devlist[i]); if ((error = device_delete_child(dev, devlist[i])) != 0) { free(devlist, M_TEMP); return (error); } sc->codecs[cad].dev = NULL; } free(devlist, M_TEMP); hdac_lock(sc); hdac_reset(sc, 0); hdac_unlock(sc); taskqueue_drain(taskqueue_thread, &sc->unsolq_task); hdac_irq_free(sc); for (i = 0; i < sc->num_ss; i++) hdac_dma_free(sc, &sc->streams[i].bdl); free(sc->streams, M_HDAC); hdac_dma_free(sc, &sc->pos_dma); hdac_dma_free(sc, &sc->rirb_dma); hdac_dma_free(sc, &sc->corb_dma); if (sc->chan_dmat != NULL) { bus_dma_tag_destroy(sc->chan_dmat); sc->chan_dmat = NULL; } hdac_mem_free(sc); snd_mtxfree(sc->lock); return (0); } static bus_dma_tag_t hdac_get_dma_tag(device_t dev, device_t child) { struct hdac_softc *sc = device_get_softc(dev); return (sc->chan_dmat); } static int hdac_print_child(device_t dev, device_t child) { int retval; retval = bus_print_child_header(dev, child); retval += printf(" at cad %d", (int)(intptr_t)device_get_ivars(child)); retval += bus_print_child_footer(dev, child); return (retval); } static int hdac_child_location_str(device_t dev, device_t child, char *buf, size_t buflen) { snprintf(buf, buflen, "cad=%d", (int)(intptr_t)device_get_ivars(child)); return (0); } static int hdac_child_pnpinfo_str_method(device_t dev, device_t child, char *buf, size_t buflen) { struct hdac_softc *sc = device_get_softc(dev); nid_t cad = (uintptr_t)device_get_ivars(child); snprintf(buf, buflen, "vendor=0x%04x device=0x%04x revision=0x%02x " "stepping=0x%02x", sc->codecs[cad].vendor_id, sc->codecs[cad].device_id, sc->codecs[cad].revision_id, sc->codecs[cad].stepping_id); return (0); } static int hdac_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct hdac_softc *sc = device_get_softc(dev); nid_t cad = (uintptr_t)device_get_ivars(child); switch (which) { case HDA_IVAR_CODEC_ID: *result = cad; break; case HDA_IVAR_VENDOR_ID: *result = sc->codecs[cad].vendor_id; break; case HDA_IVAR_DEVICE_ID: *result = sc->codecs[cad].device_id; break; case HDA_IVAR_REVISION_ID: *result = sc->codecs[cad].revision_id; break; case HDA_IVAR_STEPPING_ID: *result = sc->codecs[cad].stepping_id; break; case HDA_IVAR_SUBVENDOR_ID: *result = pci_get_subvendor(dev); break; case HDA_IVAR_SUBDEVICE_ID: *result = pci_get_subdevice(dev); break; case HDA_IVAR_DMA_NOCACHE: *result = (sc->flags & HDAC_F_DMA_NOCACHE) != 0; break; default: return (ENOENT); } return (0); } static struct mtx * hdac_get_mtx(device_t dev, device_t child) { struct hdac_softc *sc = device_get_softc(dev); return (sc->lock); } static uint32_t hdac_codec_command(device_t dev, device_t child, uint32_t verb) { return (hdac_send_command(device_get_softc(dev), (intptr_t)device_get_ivars(child), verb)); } static int hdac_find_stream(struct hdac_softc *sc, int dir, int stream) { int i, ss; ss = -1; /* Allocate ISS/BSS first. */ if (dir == 0) { for (i = 0; i < sc->num_iss; i++) { if (sc->streams[i].stream == stream) { ss = i; break; } } } else { for (i = 0; i < sc->num_oss; i++) { if (sc->streams[i + sc->num_iss].stream == stream) { ss = i + sc->num_iss; break; } } } /* Fallback to BSS. */ if (ss == -1) { for (i = 0; i < sc->num_bss; i++) { if (sc->streams[i + sc->num_iss + sc->num_oss].stream == stream) { ss = i + sc->num_iss + sc->num_oss; break; } } } return (ss); } static int hdac_stream_alloc(device_t dev, device_t child, int dir, int format, int stripe, uint32_t **dmapos) { struct hdac_softc *sc = device_get_softc(dev); nid_t cad = (uintptr_t)device_get_ivars(child); int stream, ss, bw, maxbw, prevbw; /* Look for empty stream. */ ss = hdac_find_stream(sc, dir, 0); /* Return if found nothing. */ if (ss < 0) return (0); /* Check bus bandwidth. */ bw = hdac_bdata_rate(format, dir); if (dir == 1) { bw *= 1 << (sc->num_sdo - stripe); prevbw = sc->sdo_bw_used; maxbw = 48000 * 960 * (1 << sc->num_sdo); } else { prevbw = sc->codecs[cad].sdi_bw_used; maxbw = 48000 * 464; } HDA_BOOTHVERBOSE( device_printf(dev, "%dKbps of %dKbps bandwidth used%s\n", (bw + prevbw) / 1000, maxbw / 1000, bw + prevbw > maxbw ? " -- OVERFLOW!" : ""); ); if (bw + prevbw > maxbw) return (0); if (dir == 1) sc->sdo_bw_used += bw; else sc->codecs[cad].sdi_bw_used += bw; /* Allocate stream number */ if (ss >= sc->num_iss + sc->num_oss) stream = 15 - (ss - sc->num_iss + sc->num_oss); else if (ss >= sc->num_iss) stream = ss - sc->num_iss + 1; else stream = ss + 1; sc->streams[ss].dev = child; sc->streams[ss].dir = dir; sc->streams[ss].stream = stream; sc->streams[ss].bw = bw; sc->streams[ss].format = format; sc->streams[ss].stripe = stripe; if (dmapos != NULL) { if (sc->pos_dma.dma_vaddr != NULL) *dmapos = (uint32_t *)(sc->pos_dma.dma_vaddr + ss * 8); else *dmapos = NULL; } return (stream); } static void hdac_stream_free(device_t dev, device_t child, int dir, int stream) { struct hdac_softc *sc = device_get_softc(dev); nid_t cad = (uintptr_t)device_get_ivars(child); int ss; ss = hdac_find_stream(sc, dir, stream); KASSERT(ss >= 0, ("Free for not allocated stream (%d/%d)\n", dir, stream)); if (dir == 1) sc->sdo_bw_used -= sc->streams[ss].bw; else sc->codecs[cad].sdi_bw_used -= sc->streams[ss].bw; sc->streams[ss].stream = 0; sc->streams[ss].dev = NULL; } static int hdac_stream_start(device_t dev, device_t child, int dir, int stream, bus_addr_t buf, int blksz, int blkcnt) { struct hdac_softc *sc = device_get_softc(dev); struct hdac_bdle *bdle; uint64_t addr; int i, ss, off; uint32_t ctl; ss = hdac_find_stream(sc, dir, stream); KASSERT(ss >= 0, ("Start for not allocated stream (%d/%d)\n", dir, stream)); addr = (uint64_t)buf; bdle = (struct hdac_bdle *)sc->streams[ss].bdl.dma_vaddr; for (i = 0; i < blkcnt; i++, bdle++) { bdle->addrl = (uint32_t)addr; bdle->addrh = (uint32_t)(addr >> 32); bdle->len = blksz; bdle->ioc = 1; addr += blksz; } off = ss << 5; HDAC_WRITE_4(&sc->mem, off + HDAC_SDCBL, blksz * blkcnt); HDAC_WRITE_2(&sc->mem, off + HDAC_SDLVI, blkcnt - 1); addr = sc->streams[ss].bdl.dma_paddr; HDAC_WRITE_4(&sc->mem, off + HDAC_SDBDPL, (uint32_t)addr); HDAC_WRITE_4(&sc->mem, off + HDAC_SDBDPU, (uint32_t)(addr >> 32)); ctl = HDAC_READ_1(&sc->mem, off + HDAC_SDCTL2); if (dir) ctl |= HDAC_SDCTL2_DIR; else ctl &= ~HDAC_SDCTL2_DIR; ctl &= ~HDAC_SDCTL2_STRM_MASK; ctl |= stream << HDAC_SDCTL2_STRM_SHIFT; ctl &= ~HDAC_SDCTL2_STRIPE_MASK; ctl |= sc->streams[ss].stripe << HDAC_SDCTL2_STRIPE_SHIFT; HDAC_WRITE_1(&sc->mem, off + HDAC_SDCTL2, ctl); HDAC_WRITE_2(&sc->mem, off + HDAC_SDFMT, sc->streams[ss].format); ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL); ctl |= 1 << ss; HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl); HDAC_WRITE_1(&sc->mem, off + HDAC_SDSTS, HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS); ctl = HDAC_READ_1(&sc->mem, off + HDAC_SDCTL0); ctl |= HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE | HDAC_SDCTL_RUN; HDAC_WRITE_1(&sc->mem, off + HDAC_SDCTL0, ctl); sc->streams[ss].blksz = blksz; sc->streams[ss].running = 1; hdac_poll_reinit(sc); return (0); } static void hdac_stream_stop(device_t dev, device_t child, int dir, int stream) { struct hdac_softc *sc = device_get_softc(dev); int ss, off; uint32_t ctl; ss = hdac_find_stream(sc, dir, stream); KASSERT(ss >= 0, ("Stop for not allocated stream (%d/%d)\n", dir, stream)); off = ss << 5; ctl = HDAC_READ_1(&sc->mem, off + HDAC_SDCTL0); ctl &= ~(HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE | HDAC_SDCTL_RUN); HDAC_WRITE_1(&sc->mem, off + HDAC_SDCTL0, ctl); ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL); ctl &= ~(1 << ss); HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl); sc->streams[ss].running = 0; hdac_poll_reinit(sc); } static void hdac_stream_reset(device_t dev, device_t child, int dir, int stream) { struct hdac_softc *sc = device_get_softc(dev); int timeout = 1000; int to = timeout; int ss, off; uint32_t ctl; ss = hdac_find_stream(sc, dir, stream); KASSERT(ss >= 0, ("Reset for not allocated stream (%d/%d)\n", dir, stream)); off = ss << 5; ctl = HDAC_READ_1(&sc->mem, off + HDAC_SDCTL0); ctl |= HDAC_SDCTL_SRST; HDAC_WRITE_1(&sc->mem, off + HDAC_SDCTL0, ctl); do { ctl = HDAC_READ_1(&sc->mem, off + HDAC_SDCTL0); if (ctl & HDAC_SDCTL_SRST) break; DELAY(10); } while (--to); if (!(ctl & HDAC_SDCTL_SRST)) device_printf(dev, "Reset setting timeout\n"); ctl &= ~HDAC_SDCTL_SRST; HDAC_WRITE_1(&sc->mem, off + HDAC_SDCTL0, ctl); to = timeout; do { ctl = HDAC_READ_1(&sc->mem, off + HDAC_SDCTL0); if (!(ctl & HDAC_SDCTL_SRST)) break; DELAY(10); } while (--to); if (ctl & HDAC_SDCTL_SRST) device_printf(dev, "Reset timeout!\n"); } static uint32_t hdac_stream_getptr(device_t dev, device_t child, int dir, int stream) { struct hdac_softc *sc = device_get_softc(dev); int ss, off; ss = hdac_find_stream(sc, dir, stream); KASSERT(ss >= 0, ("Reset for not allocated stream (%d/%d)\n", dir, stream)); off = ss << 5; return (HDAC_READ_4(&sc->mem, off + HDAC_SDLPIB)); } static int hdac_unsol_alloc(device_t dev, device_t child, int tag) { struct hdac_softc *sc = device_get_softc(dev); sc->unsol_registered++; hdac_poll_reinit(sc); return (tag); } static void hdac_unsol_free(device_t dev, device_t child, int tag) { struct hdac_softc *sc = device_get_softc(dev); sc->unsol_registered--; hdac_poll_reinit(sc); } static device_method_t hdac_methods[] = { /* device interface */ DEVMETHOD(device_probe, hdac_probe), DEVMETHOD(device_attach, hdac_attach), DEVMETHOD(device_detach, hdac_detach), DEVMETHOD(device_suspend, hdac_suspend), DEVMETHOD(device_resume, hdac_resume), /* Bus interface */ DEVMETHOD(bus_get_dma_tag, hdac_get_dma_tag), DEVMETHOD(bus_print_child, hdac_print_child), DEVMETHOD(bus_child_location_str, hdac_child_location_str), DEVMETHOD(bus_child_pnpinfo_str, hdac_child_pnpinfo_str_method), DEVMETHOD(bus_read_ivar, hdac_read_ivar), DEVMETHOD(hdac_get_mtx, hdac_get_mtx), DEVMETHOD(hdac_codec_command, hdac_codec_command), DEVMETHOD(hdac_stream_alloc, hdac_stream_alloc), DEVMETHOD(hdac_stream_free, hdac_stream_free), DEVMETHOD(hdac_stream_start, hdac_stream_start), DEVMETHOD(hdac_stream_stop, hdac_stream_stop), DEVMETHOD(hdac_stream_reset, hdac_stream_reset), DEVMETHOD(hdac_stream_getptr, hdac_stream_getptr), DEVMETHOD(hdac_unsol_alloc, hdac_unsol_alloc), DEVMETHOD(hdac_unsol_free, hdac_unsol_free), DEVMETHOD_END }; static driver_t hdac_driver = { "hdac", hdac_methods, sizeof(struct hdac_softc), }; static devclass_t hdac_devclass; DRIVER_MODULE(snd_hda, pci, hdac_driver, hdac_devclass, NULL, NULL); Index: head/sys/dev/sound/pci/hda/hdac.h =================================================================== --- head/sys/dev/sound/pci/hda/hdac.h (revision 275100) +++ head/sys/dev/sound/pci/hda/hdac.h (revision 275101) @@ -1,707 +1,708 @@ /*- * Copyright (c) 2006 Stephane E. Potvin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _HDAC_H_ #define _HDAC_H_ #include "hdac_if.h" /**************************************************************************** * Miscellanious defines ****************************************************************************/ /* Controller models */ #define HDA_MODEL_CONSTRUCT(vendor, model) \ (((uint32_t)(model) << 16) | ((vendor##_VENDORID) & 0xffff)) /* Intel */ #define INTEL_VENDORID 0x8086 #define HDA_INTEL_OAK HDA_MODEL_CONSTRUCT(INTEL, 0x080a) #define HDA_INTEL_BAY HDA_MODEL_CONSTRUCT(INTEL, 0x0f04) #define HDA_INTEL_HSW1 HDA_MODEL_CONSTRUCT(INTEL, 0x0a0c) #define HDA_INTEL_HSW2 HDA_MODEL_CONSTRUCT(INTEL, 0x0c0c) #define HDA_INTEL_HSW3 HDA_MODEL_CONSTRUCT(INTEL, 0x0d0c) #define HDA_INTEL_CPT HDA_MODEL_CONSTRUCT(INTEL, 0x1c20) #define HDA_INTEL_PATSBURG HDA_MODEL_CONSTRUCT(INTEL, 0x1d20) #define HDA_INTEL_PPT1 HDA_MODEL_CONSTRUCT(INTEL, 0x1e20) #define HDA_INTEL_82801F HDA_MODEL_CONSTRUCT(INTEL, 0x2668) #define HDA_INTEL_63XXESB HDA_MODEL_CONSTRUCT(INTEL, 0x269a) #define HDA_INTEL_82801G HDA_MODEL_CONSTRUCT(INTEL, 0x27d8) #define HDA_INTEL_82801H HDA_MODEL_CONSTRUCT(INTEL, 0x284b) #define HDA_INTEL_82801I HDA_MODEL_CONSTRUCT(INTEL, 0x293e) #define HDA_INTEL_82801JI HDA_MODEL_CONSTRUCT(INTEL, 0x3a3e) #define HDA_INTEL_82801JD HDA_MODEL_CONSTRUCT(INTEL, 0x3a6e) #define HDA_INTEL_PCH HDA_MODEL_CONSTRUCT(INTEL, 0x3b56) #define HDA_INTEL_PCH2 HDA_MODEL_CONSTRUCT(INTEL, 0x3b57) #define HDA_INTEL_MACBOOKPRO92 HDA_MODEL_CONSTRUCT(INTEL, 0x7270) #define HDA_INTEL_SCH HDA_MODEL_CONSTRUCT(INTEL, 0x811b) #define HDA_INTEL_LPT1 HDA_MODEL_CONSTRUCT(INTEL, 0x8c20) #define HDA_INTEL_LPT2 HDA_MODEL_CONSTRUCT(INTEL, 0x8c21) +#define HDA_INTEL_WCPT HDA_MODEL_CONSTRUCT(INTEL, 0x8ca0) #define HDA_INTEL_WELLS1 HDA_MODEL_CONSTRUCT(INTEL, 0x8d20) #define HDA_INTEL_WELLS2 HDA_MODEL_CONSTRUCT(INTEL, 0x8d21) #define HDA_INTEL_LPTLP1 HDA_MODEL_CONSTRUCT(INTEL, 0x9c20) #define HDA_INTEL_LPTLP2 HDA_MODEL_CONSTRUCT(INTEL, 0x9c21) #define HDA_INTEL_ALL HDA_MODEL_CONSTRUCT(INTEL, 0xffff) /* Nvidia */ #define NVIDIA_VENDORID 0x10de #define HDA_NVIDIA_MCP51 HDA_MODEL_CONSTRUCT(NVIDIA, 0x026c) #define HDA_NVIDIA_MCP55 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0371) #define HDA_NVIDIA_MCP61_1 HDA_MODEL_CONSTRUCT(NVIDIA, 0x03e4) #define HDA_NVIDIA_MCP61_2 HDA_MODEL_CONSTRUCT(NVIDIA, 0x03f0) #define HDA_NVIDIA_MCP65_1 HDA_MODEL_CONSTRUCT(NVIDIA, 0x044a) #define HDA_NVIDIA_MCP65_2 HDA_MODEL_CONSTRUCT(NVIDIA, 0x044b) #define HDA_NVIDIA_MCP67_1 HDA_MODEL_CONSTRUCT(NVIDIA, 0x055c) #define HDA_NVIDIA_MCP67_2 HDA_MODEL_CONSTRUCT(NVIDIA, 0x055d) #define HDA_NVIDIA_MCP78_1 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0774) #define HDA_NVIDIA_MCP78_2 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0775) #define HDA_NVIDIA_MCP78_3 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0776) #define HDA_NVIDIA_MCP78_4 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0777) #define HDA_NVIDIA_MCP73_1 HDA_MODEL_CONSTRUCT(NVIDIA, 0x07fc) #define HDA_NVIDIA_MCP73_2 HDA_MODEL_CONSTRUCT(NVIDIA, 0x07fd) #define HDA_NVIDIA_MCP79_1 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0ac0) #define HDA_NVIDIA_MCP79_2 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0ac1) #define HDA_NVIDIA_MCP79_3 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0ac2) #define HDA_NVIDIA_MCP79_4 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0ac3) #define HDA_NVIDIA_0BE2 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0be2) #define HDA_NVIDIA_0BE3 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0be3) #define HDA_NVIDIA_0BE4 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0be4) #define HDA_NVIDIA_GT100 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0be5) #define HDA_NVIDIA_GT106 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0be9) #define HDA_NVIDIA_GT108 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0bea) #define HDA_NVIDIA_GT104 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0beb) #define HDA_NVIDIA_GT116 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0bee) #define HDA_NVIDIA_MCP89_1 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0d94) #define HDA_NVIDIA_MCP89_2 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0d95) #define HDA_NVIDIA_MCP89_3 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0d96) #define HDA_NVIDIA_MCP89_4 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0d97) #define HDA_NVIDIA_GF119 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0e08) #define HDA_NVIDIA_GF110_1 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0e09) #define HDA_NVIDIA_GF110_2 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0e0c) #define HDA_NVIDIA_ALL HDA_MODEL_CONSTRUCT(NVIDIA, 0xffff) /* ATI */ #define ATI_VENDORID 0x1002 #define HDA_ATI_SB450 HDA_MODEL_CONSTRUCT(ATI, 0x437b) #define HDA_ATI_SB600 HDA_MODEL_CONSTRUCT(ATI, 0x4383) #define HDA_ATI_RS600 HDA_MODEL_CONSTRUCT(ATI, 0x793b) #define HDA_ATI_RS690 HDA_MODEL_CONSTRUCT(ATI, 0x7919) #define HDA_ATI_RS780 HDA_MODEL_CONSTRUCT(ATI, 0x960f) #define HDA_ATI_R600 HDA_MODEL_CONSTRUCT(ATI, 0xaa00) #define HDA_ATI_RV630 HDA_MODEL_CONSTRUCT(ATI, 0xaa08) #define HDA_ATI_RV610 HDA_MODEL_CONSTRUCT(ATI, 0xaa10) #define HDA_ATI_RV670 HDA_MODEL_CONSTRUCT(ATI, 0xaa18) #define HDA_ATI_RV635 HDA_MODEL_CONSTRUCT(ATI, 0xaa20) #define HDA_ATI_RV620 HDA_MODEL_CONSTRUCT(ATI, 0xaa28) #define HDA_ATI_RV770 HDA_MODEL_CONSTRUCT(ATI, 0xaa30) #define HDA_ATI_RV730 HDA_MODEL_CONSTRUCT(ATI, 0xaa38) #define HDA_ATI_RV710 HDA_MODEL_CONSTRUCT(ATI, 0xaa40) #define HDA_ATI_RV740 HDA_MODEL_CONSTRUCT(ATI, 0xaa48) #define HDA_ATI_RV870 HDA_MODEL_CONSTRUCT(ATI, 0xaa50) #define HDA_ATI_RV840 HDA_MODEL_CONSTRUCT(ATI, 0xaa58) #define HDA_ATI_RV830 HDA_MODEL_CONSTRUCT(ATI, 0xaa60) #define HDA_ATI_RV810 HDA_MODEL_CONSTRUCT(ATI, 0xaa68) #define HDA_ATI_RV970 HDA_MODEL_CONSTRUCT(ATI, 0xaa80) #define HDA_ATI_RV940 HDA_MODEL_CONSTRUCT(ATI, 0xaa88) #define HDA_ATI_RV930 HDA_MODEL_CONSTRUCT(ATI, 0xaa90) #define HDA_ATI_RV910 HDA_MODEL_CONSTRUCT(ATI, 0xaa98) #define HDA_ATI_R1000 HDA_MODEL_CONSTRUCT(ATI, 0xaaa0) #define HDA_ATI_ALL HDA_MODEL_CONSTRUCT(ATI, 0xffff) /* RDC */ #define RDC_VENDORID 0x17f3 #define HDA_RDC_M3010 HDA_MODEL_CONSTRUCT(RDC, 0x3010) /* VIA */ #define VIA_VENDORID 0x1106 #define HDA_VIA_VT82XX HDA_MODEL_CONSTRUCT(VIA, 0x3288) #define HDA_VIA_ALL HDA_MODEL_CONSTRUCT(VIA, 0xffff) /* SiS */ #define SIS_VENDORID 0x1039 #define HDA_SIS_966 HDA_MODEL_CONSTRUCT(SIS, 0x7502) #define HDA_SIS_ALL HDA_MODEL_CONSTRUCT(SIS, 0xffff) /* ULI */ #define ULI_VENDORID 0x10b9 #define HDA_ULI_M5461 HDA_MODEL_CONSTRUCT(ULI, 0x5461) #define HDA_ULI_ALL HDA_MODEL_CONSTRUCT(ULI, 0xffff) /* OEM/subvendors */ /* Intel */ #define INTEL_DH87RL_SUBVENDOR HDA_MODEL_CONSTRUCT(INTEL, 0x204a) #define INTEL_D101GGC_SUBVENDOR HDA_MODEL_CONSTRUCT(INTEL, 0xd600) /* HP/Compaq */ #define HP_VENDORID 0x103c #define HP_V3000_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x30b5) #define HP_NX7400_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x30a2) #define HP_NX6310_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x30aa) #define HP_NX6325_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x30b0) #define HP_XW4300_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x3013) #define HP_3010_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x3010) #define HP_DV5000_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x30a5) #define HP_DC7700S_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x2801) #define HP_DC7700_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x2802) #define HP_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0xffff) /* What is wrong with XN 2563 anyway? (Got the picture ?) */ #define HP_NX6325_SUBVENDORX 0x103c30b0 /* Dell */ #define DELL_VENDORID 0x1028 #define DELL_D630_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x01f9) #define DELL_D820_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x01cc) #define DELL_V1400_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x0227) #define DELL_V1500_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x0228) #define DELL_I1300_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x01c9) #define DELL_XPSM1210_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x01d7) #define DELL_OPLX745_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x01da) #define DELL_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0xffff) /* Clevo */ #define CLEVO_VENDORID 0x1558 #define CLEVO_D900T_SUBVENDOR HDA_MODEL_CONSTRUCT(CLEVO, 0x0900) #define CLEVO_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(CLEVO, 0xffff) /* Acer */ #define ACER_VENDORID 0x1025 #define ACER_A5050_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x010f) #define ACER_A4520_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x0127) #define ACER_A4710_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x012f) #define ACER_A4715_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x0133) #define ACER_3681WXM_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x0110) #define ACER_T6292_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x011b) #define ACER_T5320_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x011f) #define ACER_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0xffff) /* Asus */ #define ASUS_VENDORID 0x1043 #define ASUS_A8X_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1153) #define ASUS_U5F_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1263) #define ASUS_W6F_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1263) #define ASUS_A7M_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1323) #define ASUS_F3JC_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1338) #define ASUS_G2K_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1339) #define ASUS_A7T_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x13c2) #define ASUS_UX31A_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1517) #define ASUS_W2J_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1971) #define ASUS_M5200_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1993) #define ASUS_P5PL2_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x817f) #define ASUS_P1AH2_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x81cb) #define ASUS_M2NPVMX_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x81cb) #define ASUS_M2V_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x81e7) #define ASUS_P5BWD_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x81ec) #define ASUS_M2N_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x8234) #define ASUS_A8NVMCSM_SUBVENDOR HDA_MODEL_CONSTRUCT(NVIDIA, 0xcb84) #define ASUS_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0xffff) /* IBM / Lenovo */ #define IBM_VENDORID 0x1014 #define IBM_M52_SUBVENDOR HDA_MODEL_CONSTRUCT(IBM, 0x02f6) #define IBM_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(IBM, 0xffff) /* Lenovo */ #define LENOVO_VENDORID 0x17aa #define LENOVO_3KN100_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x2066) #define LENOVO_3KN200_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x384e) #define LENOVO_B450_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x3a0d) #define LENOVO_TCA55_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x1015) #define LENOVO_X1_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x21e8) #define LENOVO_X1CRBN_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x21f9) #define LENOVO_X220_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x21da) #define LENOVO_X300_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x20ac) #define LENOVO_T400_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x20f2) #define LENOVO_T420_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x21ce) #define LENOVO_T430_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x21f3) #define LENOVO_T430S_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x21fb) #define LENOVO_T520_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x21cf) #define LENOVO_T530_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x21f6) #define LENOVO_G580_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x3977) #define LENOVO_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0xffff) /* Samsung */ #define SAMSUNG_VENDORID 0x144d #define SAMSUNG_Q1_SUBVENDOR HDA_MODEL_CONSTRUCT(SAMSUNG, 0xc027) #define SAMSUNG_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(SAMSUNG, 0xffff) /* Medion ? */ #define MEDION_VENDORID 0x161f #define MEDION_MD95257_SUBVENDOR HDA_MODEL_CONSTRUCT(MEDION, 0x203d) #define MEDION_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(MEDION, 0xffff) /* Apple Computer Inc. */ #define APPLE_VENDORID 0x106b #define APPLE_MB3_SUBVENDOR HDA_MODEL_CONSTRUCT(APPLE, 0x00a1) /* Sony */ #define SONY_VENDORID 0x104d #define SONY_S5_SUBVENDOR HDA_MODEL_CONSTRUCT(SONY, 0x81cc) #define SONY_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(SONY, 0xffff) /* * Apple Intel MacXXXX seems using Sigmatel codec/vendor id * instead of their own, which is beyond my comprehension * (see HDA_CODEC_STAC9221 below). */ #define APPLE_INTEL_MAC 0x76808384 #define APPLE_MACBOOKAIR31 0x0d9410de #define APPLE_MACBOOKPRO55 0xcb7910de #define APPLE_MACBOOKPRO71 0xcb8910de /* LG Electronics */ #define LG_VENDORID 0x1854 #define LG_LW20_SUBVENDOR HDA_MODEL_CONSTRUCT(LG, 0x0018) #define LG_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(LG, 0xffff) /* Fujitsu Siemens */ #define FS_VENDORID 0x1734 #define FS_PA1510_SUBVENDOR HDA_MODEL_CONSTRUCT(FS, 0x10b8) #define FS_SI1848_SUBVENDOR HDA_MODEL_CONSTRUCT(FS, 0x10cd) #define FS_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(FS, 0xffff) /* Fujitsu Limited */ #define FL_VENDORID 0x10cf #define FL_S7020D_SUBVENDOR HDA_MODEL_CONSTRUCT(FL, 0x1326) #define FL_U1010_SUBVENDOR HDA_MODEL_CONSTRUCT(FL, 0x142d) #define FL_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(FL, 0xffff) /* Toshiba */ #define TOSHIBA_VENDORID 0x1179 #define TOSHIBA_U200_SUBVENDOR HDA_MODEL_CONSTRUCT(TOSHIBA, 0x0001) #define TOSHIBA_A135_SUBVENDOR HDA_MODEL_CONSTRUCT(TOSHIBA, 0xff01) #define TOSHIBA_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(TOSHIBA, 0xffff) /* Micro-Star International (MSI) */ #define MSI_VENDORID 0x1462 #define MSI_MS1034_SUBVENDOR HDA_MODEL_CONSTRUCT(MSI, 0x0349) #define MSI_MS034A_SUBVENDOR HDA_MODEL_CONSTRUCT(MSI, 0x034a) #define MSI_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(MSI, 0xffff) /* Giga-Byte Technology */ #define GB_VENDORID 0x1458 #define GB_G33S2H_SUBVENDOR HDA_MODEL_CONSTRUCT(GB, 0xa022) #define GP_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(GB, 0xffff) /* Uniwill ? */ #define UNIWILL_VENDORID 0x1584 #define UNIWILL_9075_SUBVENDOR HDA_MODEL_CONSTRUCT(UNIWILL, 0x9075) #define UNIWILL_9080_SUBVENDOR HDA_MODEL_CONSTRUCT(UNIWILL, 0x9080) /* All codecs you can eat... */ #define HDA_CODEC_CONSTRUCT(vendor, id) \ (((uint32_t)(vendor##_VENDORID) << 16) | ((id) & 0xffff)) /* Cirrus Logic */ #define CIRRUSLOGIC_VENDORID 0x1013 #define HDA_CODEC_CS4206 HDA_CODEC_CONSTRUCT(CIRRUSLOGIC, 0x4206) #define HDA_CODEC_CS4207 HDA_CODEC_CONSTRUCT(CIRRUSLOGIC, 0x4207) #define HDA_CODEC_CS4210 HDA_CODEC_CONSTRUCT(CIRRUSLOGIC, 0x4210) #define HDA_CODEC_CSXXXX HDA_CODEC_CONSTRUCT(CIRRUSLOGIC, 0xffff) /* Realtek */ #define REALTEK_VENDORID 0x10ec #define HDA_CODEC_ALC221 HDA_CODEC_CONSTRUCT(REALTEK, 0x0221) #define HDA_CODEC_ALC260 HDA_CODEC_CONSTRUCT(REALTEK, 0x0260) #define HDA_CODEC_ALC262 HDA_CODEC_CONSTRUCT(REALTEK, 0x0262) #define HDA_CODEC_ALC267 HDA_CODEC_CONSTRUCT(REALTEK, 0x0267) #define HDA_CODEC_ALC268 HDA_CODEC_CONSTRUCT(REALTEK, 0x0268) #define HDA_CODEC_ALC269 HDA_CODEC_CONSTRUCT(REALTEK, 0x0269) #define HDA_CODEC_ALC270 HDA_CODEC_CONSTRUCT(REALTEK, 0x0270) #define HDA_CODEC_ALC272 HDA_CODEC_CONSTRUCT(REALTEK, 0x0272) #define HDA_CODEC_ALC273 HDA_CODEC_CONSTRUCT(REALTEK, 0x0273) #define HDA_CODEC_ALC275 HDA_CODEC_CONSTRUCT(REALTEK, 0x0275) #define HDA_CODEC_ALC276 HDA_CODEC_CONSTRUCT(REALTEK, 0x0276) #define HDA_CODEC_ALC660 HDA_CODEC_CONSTRUCT(REALTEK, 0x0660) #define HDA_CODEC_ALC662 HDA_CODEC_CONSTRUCT(REALTEK, 0x0662) #define HDA_CODEC_ALC663 HDA_CODEC_CONSTRUCT(REALTEK, 0x0663) #define HDA_CODEC_ALC665 HDA_CODEC_CONSTRUCT(REALTEK, 0x0665) #define HDA_CODEC_ALC670 HDA_CODEC_CONSTRUCT(REALTEK, 0x0670) #define HDA_CODEC_ALC680 HDA_CODEC_CONSTRUCT(REALTEK, 0x0680) #define HDA_CODEC_ALC861 HDA_CODEC_CONSTRUCT(REALTEK, 0x0861) #define HDA_CODEC_ALC861VD HDA_CODEC_CONSTRUCT(REALTEK, 0x0862) #define HDA_CODEC_ALC880 HDA_CODEC_CONSTRUCT(REALTEK, 0x0880) #define HDA_CODEC_ALC882 HDA_CODEC_CONSTRUCT(REALTEK, 0x0882) #define HDA_CODEC_ALC883 HDA_CODEC_CONSTRUCT(REALTEK, 0x0883) #define HDA_CODEC_ALC885 HDA_CODEC_CONSTRUCT(REALTEK, 0x0885) #define HDA_CODEC_ALC887 HDA_CODEC_CONSTRUCT(REALTEK, 0x0887) #define HDA_CODEC_ALC888 HDA_CODEC_CONSTRUCT(REALTEK, 0x0888) #define HDA_CODEC_ALC889 HDA_CODEC_CONSTRUCT(REALTEK, 0x0889) #define HDA_CODEC_ALC892 HDA_CODEC_CONSTRUCT(REALTEK, 0x0892) #define HDA_CODEC_ALC899 HDA_CODEC_CONSTRUCT(REALTEK, 0x0899) #define HDA_CODEC_ALCXXXX HDA_CODEC_CONSTRUCT(REALTEK, 0xffff) /* Motorola */ #define MOTO_VENDORID 0x1057 #define HDA_CODEC_MOTOXXXX HDA_CODEC_CONSTRUCT(MOTO, 0xffff) /* Creative */ #define CREATIVE_VENDORID 0x1102 #define HDA_CODEC_CA0110 HDA_CODEC_CONSTRUCT(CREATIVE, 0x000a) #define HDA_CODEC_CA0110_2 HDA_CODEC_CONSTRUCT(CREATIVE, 0x000b) #define HDA_CODEC_SB0880 HDA_CODEC_CONSTRUCT(CREATIVE, 0x000d) #define HDA_CODEC_CA0132 HDA_CODEC_CONSTRUCT(CREATIVE, 0x0011) #define HDA_CODEC_CAXXXX HDA_CODEC_CONSTRUCT(CREATIVE, 0xffff) /* Analog Devices */ #define ANALOGDEVICES_VENDORID 0x11d4 #define HDA_CODEC_AD1884A HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x184a) #define HDA_CODEC_AD1882 HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1882) #define HDA_CODEC_AD1883 HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1883) #define HDA_CODEC_AD1884 HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1884) #define HDA_CODEC_AD1984A HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x194a) #define HDA_CODEC_AD1984B HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x194b) #define HDA_CODEC_AD1981HD HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1981) #define HDA_CODEC_AD1983 HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1983) #define HDA_CODEC_AD1984 HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1984) #define HDA_CODEC_AD1986A HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1986) #define HDA_CODEC_AD1987 HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1987) #define HDA_CODEC_AD1988 HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1988) #define HDA_CODEC_AD1988B HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x198b) #define HDA_CODEC_AD1882A HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x882a) #define HDA_CODEC_AD1989A HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x989a) #define HDA_CODEC_AD1989B HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x989b) #define HDA_CODEC_ADXXXX HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0xffff) /* CMedia */ #define CMEDIA_VENDORID 0x13f6 #define HDA_CODEC_CMI9880 HDA_CODEC_CONSTRUCT(CMEDIA, 0x9880) #define HDA_CODEC_CMIXXXX HDA_CODEC_CONSTRUCT(CMEDIA, 0xffff) #define CMEDIA2_VENDORID 0x434d #define HDA_CODEC_CMI98802 HDA_CODEC_CONSTRUCT(CMEDIA2, 0x4980) #define HDA_CODEC_CMIXXXX2 HDA_CODEC_CONSTRUCT(CMEDIA2, 0xffff) /* Sigmatel */ #define SIGMATEL_VENDORID 0x8384 #define HDA_CODEC_STAC9230X HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7612) #define HDA_CODEC_STAC9230D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7613) #define HDA_CODEC_STAC9229X HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7614) #define HDA_CODEC_STAC9229D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7615) #define HDA_CODEC_STAC9228X HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7616) #define HDA_CODEC_STAC9228D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7617) #define HDA_CODEC_STAC9227X HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7618) #define HDA_CODEC_STAC9227D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7619) #define HDA_CODEC_STAC9274 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7620) #define HDA_CODEC_STAC9274D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7621) #define HDA_CODEC_STAC9273X HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7622) #define HDA_CODEC_STAC9273D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7623) #define HDA_CODEC_STAC9272X HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7624) #define HDA_CODEC_STAC9272D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7625) #define HDA_CODEC_STAC9271X HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7626) #define HDA_CODEC_STAC9271D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7627) #define HDA_CODEC_STAC9274X5NH HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7628) #define HDA_CODEC_STAC9274D5NH HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7629) #define HDA_CODEC_STAC9250 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7634) #define HDA_CODEC_STAC9251 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7636) #define HDA_CODEC_IDT92HD700X HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7638) #define HDA_CODEC_IDT92HD700D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7639) #define HDA_CODEC_IDT92HD206X HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7645) #define HDA_CODEC_IDT92HD206D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7646) #define HDA_CODEC_CXD9872RDK HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7661) #define HDA_CODEC_STAC9872AK HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7662) #define HDA_CODEC_CXD9872AKD HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7664) #define HDA_CODEC_STAC9221 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7680) #define HDA_CODEC_STAC922XD HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7681) #define HDA_CODEC_STAC9221_A2 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7682) #define HDA_CODEC_STAC9221D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7683) #define HDA_CODEC_STAC9220 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7690) #define HDA_CODEC_STAC9200D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7691) #define HDA_CODEC_IDT92HD005 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7698) #define HDA_CODEC_IDT92HD005D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7699) #define HDA_CODEC_STAC9205X HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a0) #define HDA_CODEC_STAC9205D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a1) #define HDA_CODEC_STAC9204X HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a2) #define HDA_CODEC_STAC9204D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a3) #define HDA_CODEC_STAC9255 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a4) #define HDA_CODEC_STAC9255D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a5) #define HDA_CODEC_STAC9254 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a6) #define HDA_CODEC_STAC9254D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a7) #define HDA_CODEC_STAC9220_A2 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7880) #define HDA_CODEC_STAC9220_A1 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7882) #define HDA_CODEC_STACXXXX HDA_CODEC_CONSTRUCT(SIGMATEL, 0xffff) /* IDT */ #define IDT_VENDORID 0x111d #define HDA_CODEC_IDT92HD75BX HDA_CODEC_CONSTRUCT(IDT, 0x7603) #define HDA_CODEC_IDT92HD83C1X HDA_CODEC_CONSTRUCT(IDT, 0x7604) #define HDA_CODEC_IDT92HD81B1X HDA_CODEC_CONSTRUCT(IDT, 0x7605) #define HDA_CODEC_IDT92HD75B3 HDA_CODEC_CONSTRUCT(IDT, 0x7608) #define HDA_CODEC_IDT92HD73D1 HDA_CODEC_CONSTRUCT(IDT, 0x7674) #define HDA_CODEC_IDT92HD73C1 HDA_CODEC_CONSTRUCT(IDT, 0x7675) #define HDA_CODEC_IDT92HD73E1 HDA_CODEC_CONSTRUCT(IDT, 0x7676) #define HDA_CODEC_IDT92HD71B8 HDA_CODEC_CONSTRUCT(IDT, 0x76b0) #define HDA_CODEC_IDT92HD71B8_2 HDA_CODEC_CONSTRUCT(IDT, 0x76b1) #define HDA_CODEC_IDT92HD71B7 HDA_CODEC_CONSTRUCT(IDT, 0x76b2) #define HDA_CODEC_IDT92HD71B7_2 HDA_CODEC_CONSTRUCT(IDT, 0x76b3) #define HDA_CODEC_IDT92HD71B6 HDA_CODEC_CONSTRUCT(IDT, 0x76b4) #define HDA_CODEC_IDT92HD71B6_2 HDA_CODEC_CONSTRUCT(IDT, 0x76b5) #define HDA_CODEC_IDT92HD71B5 HDA_CODEC_CONSTRUCT(IDT, 0x76b6) #define HDA_CODEC_IDT92HD71B5_2 HDA_CODEC_CONSTRUCT(IDT, 0x76b7) #define HDA_CODEC_IDT92HD89C3 HDA_CODEC_CONSTRUCT(IDT, 0x76c0) #define HDA_CODEC_IDT92HD89C2 HDA_CODEC_CONSTRUCT(IDT, 0x76c1) #define HDA_CODEC_IDT92HD89C1 HDA_CODEC_CONSTRUCT(IDT, 0x76c2) #define HDA_CODEC_IDT92HD89B3 HDA_CODEC_CONSTRUCT(IDT, 0x76c3) #define HDA_CODEC_IDT92HD89B2 HDA_CODEC_CONSTRUCT(IDT, 0x76c4) #define HDA_CODEC_IDT92HD89B1 HDA_CODEC_CONSTRUCT(IDT, 0x76c5) #define HDA_CODEC_IDT92HD89E3 HDA_CODEC_CONSTRUCT(IDT, 0x76c6) #define HDA_CODEC_IDT92HD89E2 HDA_CODEC_CONSTRUCT(IDT, 0x76c7) #define HDA_CODEC_IDT92HD89E1 HDA_CODEC_CONSTRUCT(IDT, 0x76c8) #define HDA_CODEC_IDT92HD89D3 HDA_CODEC_CONSTRUCT(IDT, 0x76c9) #define HDA_CODEC_IDT92HD89D2 HDA_CODEC_CONSTRUCT(IDT, 0x76ca) #define HDA_CODEC_IDT92HD89D1 HDA_CODEC_CONSTRUCT(IDT, 0x76cb) #define HDA_CODEC_IDT92HD89F3 HDA_CODEC_CONSTRUCT(IDT, 0x76cc) #define HDA_CODEC_IDT92HD89F2 HDA_CODEC_CONSTRUCT(IDT, 0x76cd) #define HDA_CODEC_IDT92HD89F1 HDA_CODEC_CONSTRUCT(IDT, 0x76ce) #define HDA_CODEC_IDT92HD87B1_3 HDA_CODEC_CONSTRUCT(IDT, 0x76d1) #define HDA_CODEC_IDT92HD83C1C HDA_CODEC_CONSTRUCT(IDT, 0x76d4) #define HDA_CODEC_IDT92HD81B1C HDA_CODEC_CONSTRUCT(IDT, 0x76d5) #define HDA_CODEC_IDT92HD87B2_4 HDA_CODEC_CONSTRUCT(IDT, 0x76d9) #define HDA_CODEC_IDT92HD93BXX HDA_CODEC_CONSTRUCT(IDT, 0x76df) #define HDA_CODEC_IDT92HD91BXX HDA_CODEC_CONSTRUCT(IDT, 0x76e0) #define HDA_CODEC_IDT92HD98BXX HDA_CODEC_CONSTRUCT(IDT, 0x76e3) #define HDA_CODEC_IDT92HD99BXX HDA_CODEC_CONSTRUCT(IDT, 0x76e5) #define HDA_CODEC_IDT92HD90BXX HDA_CODEC_CONSTRUCT(IDT, 0x76e7) #define HDA_CODEC_IDT92HD66B1X5 HDA_CODEC_CONSTRUCT(IDT, 0x76e8) #define HDA_CODEC_IDT92HD66B2X5 HDA_CODEC_CONSTRUCT(IDT, 0x76e9) #define HDA_CODEC_IDT92HD66B3X5 HDA_CODEC_CONSTRUCT(IDT, 0x76ea) #define HDA_CODEC_IDT92HD66C1X5 HDA_CODEC_CONSTRUCT(IDT, 0x76eb) #define HDA_CODEC_IDT92HD66C2X5 HDA_CODEC_CONSTRUCT(IDT, 0x76ec) #define HDA_CODEC_IDT92HD66C3X5 HDA_CODEC_CONSTRUCT(IDT, 0x76ed) #define HDA_CODEC_IDT92HD66B1X3 HDA_CODEC_CONSTRUCT(IDT, 0x76ee) #define HDA_CODEC_IDT92HD66B2X3 HDA_CODEC_CONSTRUCT(IDT, 0x76ef) #define HDA_CODEC_IDT92HD66B3X3 HDA_CODEC_CONSTRUCT(IDT, 0x76f0) #define HDA_CODEC_IDT92HD66C1X3 HDA_CODEC_CONSTRUCT(IDT, 0x76f1) #define HDA_CODEC_IDT92HD66C2X3 HDA_CODEC_CONSTRUCT(IDT, 0x76f2) #define HDA_CODEC_IDT92HD66C3_65 HDA_CODEC_CONSTRUCT(IDT, 0x76f3) #define HDA_CODEC_IDTXXXX HDA_CODEC_CONSTRUCT(IDT, 0xffff) /* Silicon Image */ #define SII_VENDORID 0x1095 #define HDA_CODEC_SII1390 HDA_CODEC_CONSTRUCT(SII, 0x1390) #define HDA_CODEC_SII1392 HDA_CODEC_CONSTRUCT(SII, 0x1392) #define HDA_CODEC_SIIXXXX HDA_CODEC_CONSTRUCT(SII, 0xffff) /* Lucent/Agere */ #define AGERE_VENDORID 0x11c1 #define HDA_CODEC_AGEREXXXX HDA_CODEC_CONSTRUCT(AGERE, 0xffff) /* Conexant */ #define CONEXANT_VENDORID 0x14f1 #define HDA_CODEC_CX20549 HDA_CODEC_CONSTRUCT(CONEXANT, 0x5045) #define HDA_CODEC_CX20551 HDA_CODEC_CONSTRUCT(CONEXANT, 0x5047) #define HDA_CODEC_CX20561 HDA_CODEC_CONSTRUCT(CONEXANT, 0x5051) #define HDA_CODEC_CX20582 HDA_CODEC_CONSTRUCT(CONEXANT, 0x5066) #define HDA_CODEC_CX20583 HDA_CODEC_CONSTRUCT(CONEXANT, 0x5067) #define HDA_CODEC_CX20584 HDA_CODEC_CONSTRUCT(CONEXANT, 0x5068) #define HDA_CODEC_CX20585 HDA_CODEC_CONSTRUCT(CONEXANT, 0x5069) #define HDA_CODEC_CX20588 HDA_CODEC_CONSTRUCT(CONEXANT, 0x506c) #define HDA_CODEC_CX20590 HDA_CODEC_CONSTRUCT(CONEXANT, 0x506e) #define HDA_CODEC_CX20631 HDA_CODEC_CONSTRUCT(CONEXANT, 0x5097) #define HDA_CODEC_CX20632 HDA_CODEC_CONSTRUCT(CONEXANT, 0x5098) #define HDA_CODEC_CX20641 HDA_CODEC_CONSTRUCT(CONEXANT, 0x50a1) #define HDA_CODEC_CX20642 HDA_CODEC_CONSTRUCT(CONEXANT, 0x50a2) #define HDA_CODEC_CX20651 HDA_CODEC_CONSTRUCT(CONEXANT, 0x50ab) #define HDA_CODEC_CX20652 HDA_CODEC_CONSTRUCT(CONEXANT, 0x50ac) #define HDA_CODEC_CX20664 HDA_CODEC_CONSTRUCT(CONEXANT, 0x50b8) #define HDA_CODEC_CX20665 HDA_CODEC_CONSTRUCT(CONEXANT, 0x50b9) #define HDA_CODEC_CXXXXX HDA_CODEC_CONSTRUCT(CONEXANT, 0xffff) /* VIA */ #define HDA_CODEC_VT1708_8 HDA_CODEC_CONSTRUCT(VIA, 0x1708) #define HDA_CODEC_VT1708_9 HDA_CODEC_CONSTRUCT(VIA, 0x1709) #define HDA_CODEC_VT1708_A HDA_CODEC_CONSTRUCT(VIA, 0x170a) #define HDA_CODEC_VT1708_B HDA_CODEC_CONSTRUCT(VIA, 0x170b) #define HDA_CODEC_VT1709_0 HDA_CODEC_CONSTRUCT(VIA, 0xe710) #define HDA_CODEC_VT1709_1 HDA_CODEC_CONSTRUCT(VIA, 0xe711) #define HDA_CODEC_VT1709_2 HDA_CODEC_CONSTRUCT(VIA, 0xe712) #define HDA_CODEC_VT1709_3 HDA_CODEC_CONSTRUCT(VIA, 0xe713) #define HDA_CODEC_VT1709_4 HDA_CODEC_CONSTRUCT(VIA, 0xe714) #define HDA_CODEC_VT1709_5 HDA_CODEC_CONSTRUCT(VIA, 0xe715) #define HDA_CODEC_VT1709_6 HDA_CODEC_CONSTRUCT(VIA, 0xe716) #define HDA_CODEC_VT1709_7 HDA_CODEC_CONSTRUCT(VIA, 0xe717) #define HDA_CODEC_VT1708B_0 HDA_CODEC_CONSTRUCT(VIA, 0xe720) #define HDA_CODEC_VT1708B_1 HDA_CODEC_CONSTRUCT(VIA, 0xe721) #define HDA_CODEC_VT1708B_2 HDA_CODEC_CONSTRUCT(VIA, 0xe722) #define HDA_CODEC_VT1708B_3 HDA_CODEC_CONSTRUCT(VIA, 0xe723) #define HDA_CODEC_VT1708B_4 HDA_CODEC_CONSTRUCT(VIA, 0xe724) #define HDA_CODEC_VT1708B_5 HDA_CODEC_CONSTRUCT(VIA, 0xe725) #define HDA_CODEC_VT1708B_6 HDA_CODEC_CONSTRUCT(VIA, 0xe726) #define HDA_CODEC_VT1708B_7 HDA_CODEC_CONSTRUCT(VIA, 0xe727) #define HDA_CODEC_VT1708S_0 HDA_CODEC_CONSTRUCT(VIA, 0x0397) #define HDA_CODEC_VT1708S_1 HDA_CODEC_CONSTRUCT(VIA, 0x1397) #define HDA_CODEC_VT1708S_2 HDA_CODEC_CONSTRUCT(VIA, 0x2397) #define HDA_CODEC_VT1708S_3 HDA_CODEC_CONSTRUCT(VIA, 0x3397) #define HDA_CODEC_VT1708S_4 HDA_CODEC_CONSTRUCT(VIA, 0x4397) #define HDA_CODEC_VT1708S_5 HDA_CODEC_CONSTRUCT(VIA, 0x5397) #define HDA_CODEC_VT1708S_6 HDA_CODEC_CONSTRUCT(VIA, 0x6397) #define HDA_CODEC_VT1708S_7 HDA_CODEC_CONSTRUCT(VIA, 0x7397) #define HDA_CODEC_VT1702_0 HDA_CODEC_CONSTRUCT(VIA, 0x0398) #define HDA_CODEC_VT1702_1 HDA_CODEC_CONSTRUCT(VIA, 0x1398) #define HDA_CODEC_VT1702_2 HDA_CODEC_CONSTRUCT(VIA, 0x2398) #define HDA_CODEC_VT1702_3 HDA_CODEC_CONSTRUCT(VIA, 0x3398) #define HDA_CODEC_VT1702_4 HDA_CODEC_CONSTRUCT(VIA, 0x4398) #define HDA_CODEC_VT1702_5 HDA_CODEC_CONSTRUCT(VIA, 0x5398) #define HDA_CODEC_VT1702_6 HDA_CODEC_CONSTRUCT(VIA, 0x6398) #define HDA_CODEC_VT1702_7 HDA_CODEC_CONSTRUCT(VIA, 0x7398) #define HDA_CODEC_VT1716S_0 HDA_CODEC_CONSTRUCT(VIA, 0x0433) #define HDA_CODEC_VT1716S_1 HDA_CODEC_CONSTRUCT(VIA, 0xa721) #define HDA_CODEC_VT1718S_0 HDA_CODEC_CONSTRUCT(VIA, 0x0428) #define HDA_CODEC_VT1718S_1 HDA_CODEC_CONSTRUCT(VIA, 0x4428) #define HDA_CODEC_VT1802_0 HDA_CODEC_CONSTRUCT(VIA, 0x0446) #define HDA_CODEC_VT1802_1 HDA_CODEC_CONSTRUCT(VIA, 0x8446) #define HDA_CODEC_VT1812 HDA_CODEC_CONSTRUCT(VIA, 0x0448) #define HDA_CODEC_VT1818S HDA_CODEC_CONSTRUCT(VIA, 0x0440) #define HDA_CODEC_VT1828S HDA_CODEC_CONSTRUCT(VIA, 0x4441) #define HDA_CODEC_VT2002P_0 HDA_CODEC_CONSTRUCT(VIA, 0x0438) #define HDA_CODEC_VT2002P_1 HDA_CODEC_CONSTRUCT(VIA, 0x4438) #define HDA_CODEC_VT2020 HDA_CODEC_CONSTRUCT(VIA, 0x0441) #define HDA_CODEC_VTXXXX HDA_CODEC_CONSTRUCT(VIA, 0xffff) /* ATI */ #define HDA_CODEC_ATIRS600_1 HDA_CODEC_CONSTRUCT(ATI, 0x793c) #define HDA_CODEC_ATIRS600_2 HDA_CODEC_CONSTRUCT(ATI, 0x7919) #define HDA_CODEC_ATIRS690 HDA_CODEC_CONSTRUCT(ATI, 0x791a) #define HDA_CODEC_ATIR6XX HDA_CODEC_CONSTRUCT(ATI, 0xaa01) #define HDA_CODEC_ATIXXXX HDA_CODEC_CONSTRUCT(ATI, 0xffff) /* NVIDIA */ #define HDA_CODEC_NVIDIAMCP78 HDA_CODEC_CONSTRUCT(NVIDIA, 0x0002) #define HDA_CODEC_NVIDIAMCP78_2 HDA_CODEC_CONSTRUCT(NVIDIA, 0x0003) #define HDA_CODEC_NVIDIAMCP78_3 HDA_CODEC_CONSTRUCT(NVIDIA, 0x0005) #define HDA_CODEC_NVIDIAMCP78_4 HDA_CODEC_CONSTRUCT(NVIDIA, 0x0006) #define HDA_CODEC_NVIDIAMCP7A HDA_CODEC_CONSTRUCT(NVIDIA, 0x0007) #define HDA_CODEC_NVIDIAGT220 HDA_CODEC_CONSTRUCT(NVIDIA, 0x000a) #define HDA_CODEC_NVIDIAGT21X HDA_CODEC_CONSTRUCT(NVIDIA, 0x000b) #define HDA_CODEC_NVIDIAMCP89 HDA_CODEC_CONSTRUCT(NVIDIA, 0x000c) #define HDA_CODEC_NVIDIAGT240 HDA_CODEC_CONSTRUCT(NVIDIA, 0x000d) #define HDA_CODEC_NVIDIAGTS450 HDA_CODEC_CONSTRUCT(NVIDIA, 0x0011) #define HDA_CODEC_NVIDIAGT440 HDA_CODEC_CONSTRUCT(NVIDIA, 0x0014) #define HDA_CODEC_NVIDIAGTX550 HDA_CODEC_CONSTRUCT(NVIDIA, 0x0015) #define HDA_CODEC_NVIDIAGTX570 HDA_CODEC_CONSTRUCT(NVIDIA, 0x0018) #define HDA_CODEC_NVIDIAMCP67 HDA_CODEC_CONSTRUCT(NVIDIA, 0x0067) #define HDA_CODEC_NVIDIAMCP73 HDA_CODEC_CONSTRUCT(NVIDIA, 0x8001) #define HDA_CODEC_NVIDIAXXXX HDA_CODEC_CONSTRUCT(NVIDIA, 0xffff) /* Chrontel */ #define CHRONTEL_VENDORID 0x17e8 #define HDA_CODEC_CHXXXX HDA_CODEC_CONSTRUCT(CHRONTEL, 0xffff) /* INTEL */ #define HDA_CODEC_INTELIP HDA_CODEC_CONSTRUCT(INTEL, 0x0054) #define HDA_CODEC_INTELBL HDA_CODEC_CONSTRUCT(INTEL, 0x2801) #define HDA_CODEC_INTELCA HDA_CODEC_CONSTRUCT(INTEL, 0x2802) #define HDA_CODEC_INTELEL HDA_CODEC_CONSTRUCT(INTEL, 0x2803) #define HDA_CODEC_INTELIP2 HDA_CODEC_CONSTRUCT(INTEL, 0x2804) #define HDA_CODEC_INTELCPT HDA_CODEC_CONSTRUCT(INTEL, 0x2805) #define HDA_CODEC_INTELPPT HDA_CODEC_CONSTRUCT(INTEL, 0x2806) #define HDA_CODEC_INTELHSW HDA_CODEC_CONSTRUCT(INTEL, 0x2807) #define HDA_CODEC_INTELCL HDA_CODEC_CONSTRUCT(INTEL, 0x29fb) #define HDA_CODEC_INTELXXXX HDA_CODEC_CONSTRUCT(INTEL, 0xffff) /**************************************************************************** * Helper Macros ****************************************************************************/ #define HDA_DMA_ALIGNMENT 128 #define HDA_BDL_MIN 2 #define HDA_BDL_MAX 256 #define HDA_BDL_DEFAULT HDA_BDL_MIN #define HDA_BLK_MIN HDA_DMA_ALIGNMENT #define HDA_BLK_ALIGN (~(HDA_BLK_MIN - 1)) #define HDA_BUFSZ_MIN (HDA_BDL_MIN * HDA_BLK_MIN) #define HDA_BUFSZ_MAX 262144 #define HDA_BUFSZ_DEFAULT 65536 #define HDA_GPIO_MAX 8 #define HDA_DEV_MATCH(fl, v) ((fl) == (v) || \ (fl) == 0xffffffff || \ (((fl) & 0xffff0000) == 0xffff0000 && \ ((fl) & 0x0000ffff) == ((v) & 0x0000ffff)) || \ (((fl) & 0x0000ffff) == 0x0000ffff && \ ((fl) & 0xffff0000) == ((v) & 0xffff0000))) #define HDA_MATCH_ALL 0xffffffff #define HDA_INVALID 0xffffffff #define HDA_BOOTVERBOSE(stmt) do { \ if (bootverbose != 0 || snd_verbose > 3) { \ stmt \ } \ } while (0) #define HDA_BOOTHVERBOSE(stmt) do { \ if (snd_verbose > 3) { \ stmt \ } \ } while (0) #define hda_command(dev, verb) \ HDAC_CODEC_COMMAND(device_get_parent(dev), (dev), (verb)) typedef int nid_t; /**************************************************************************** * Simplified Accessors for HDA devices ****************************************************************************/ enum hdac_device_ivars { HDA_IVAR_CODEC_ID, HDA_IVAR_NODE_ID, HDA_IVAR_VENDOR_ID, HDA_IVAR_DEVICE_ID, HDA_IVAR_REVISION_ID, HDA_IVAR_STEPPING_ID, HDA_IVAR_SUBVENDOR_ID, HDA_IVAR_SUBDEVICE_ID, HDA_IVAR_SUBSYSTEM_ID, HDA_IVAR_NODE_TYPE, HDA_IVAR_DMA_NOCACHE, }; #define HDA_ACCESSOR(var, ivar, type) \ __BUS_ACCESSOR(hda, var, HDA, ivar, type) HDA_ACCESSOR(codec_id, CODEC_ID, uint8_t); HDA_ACCESSOR(node_id, NODE_ID, uint8_t); HDA_ACCESSOR(vendor_id, VENDOR_ID, uint16_t); HDA_ACCESSOR(device_id, DEVICE_ID, uint16_t); HDA_ACCESSOR(revision_id, REVISION_ID, uint8_t); HDA_ACCESSOR(stepping_id, STEPPING_ID, uint8_t); HDA_ACCESSOR(subvendor_id, SUBVENDOR_ID, uint16_t); HDA_ACCESSOR(subdevice_id, SUBDEVICE_ID, uint16_t); HDA_ACCESSOR(subsystem_id, SUBSYSTEM_ID, uint32_t); HDA_ACCESSOR(node_type, NODE_TYPE, uint8_t); HDA_ACCESSOR(dma_nocache, DMA_NOCACHE, uint8_t); #define PCIS_MULTIMEDIA_HDA 0x03 #endif Index: head/sys/dev/uart/uart_bus_pci.c =================================================================== --- head/sys/dev/uart/uart_bus_pci.c (revision 275100) +++ head/sys/dev/uart/uart_bus_pci.c (revision 275101) @@ -1,195 +1,196 @@ /*- * Copyright (c) 2006 Marcel Moolenaar * Copyright (c) 2001 M. Warner Losh * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #define DEFAULT_RCLK 1843200 static int uart_pci_probe(device_t dev); static device_method_t uart_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uart_pci_probe), DEVMETHOD(device_attach, uart_bus_attach), DEVMETHOD(device_detach, uart_bus_detach), DEVMETHOD(device_resume, uart_bus_resume), DEVMETHOD_END }; static driver_t uart_pci_driver = { uart_driver_name, uart_pci_methods, sizeof(struct uart_softc), }; struct pci_id { uint16_t vendor; uint16_t device; uint16_t subven; uint16_t subdev; const char *desc; int rid; int rclk; }; static const struct pci_id pci_ns8250_ids[] = { { 0x1028, 0x0008, 0xffff, 0, "Dell Remote Access Card III", 0x14, 128 * DEFAULT_RCLK }, { 0x1028, 0x0012, 0xffff, 0, "Dell RAC 4 Daughter Card Virtual UART", 0x14, 128 * DEFAULT_RCLK }, { 0x1033, 0x0074, 0x1033, 0x8014, "NEC RCV56ACF 56k Voice Modem", 0x10 }, { 0x1033, 0x007d, 0x1033, 0x8012, "NEC RS232C", 0x10 }, { 0x103c, 0x1048, 0x103c, 0x1227, "HP Diva Serial [GSP] UART - Powerbar SP2", 0x10 }, { 0x103c, 0x1048, 0x103c, 0x1301, "HP Diva RMP3", 0x14 }, { 0x103c, 0x1290, 0xffff, 0, "HP Auxiliary Diva Serial Port", 0x18 }, { 0x103c, 0x3301, 0xffff, 0, "HP iLO serial port", 0x10 }, { 0x11c1, 0x0480, 0xffff, 0, "Agere Systems Venus Modem (V90, 56KFlex)", 0x14 }, { 0x115d, 0x0103, 0xffff, 0, "Xircom Cardbus Ethernet + 56k Modem", 0x10 }, { 0x1282, 0x6585, 0xffff, 0, "Davicom 56PDV PCI Modem", 0x10 }, { 0x12b9, 0x1008, 0xffff, 0, "3Com 56K FaxModem Model 5610", 0x10 }, { 0x131f, 0x1000, 0xffff, 0, "Siig CyberSerial (1-port) 16550", 0x18 }, { 0x131f, 0x1001, 0xffff, 0, "Siig CyberSerial (1-port) 16650", 0x18 }, { 0x131f, 0x1002, 0xffff, 0, "Siig CyberSerial (1-port) 16850", 0x18 }, { 0x131f, 0x2000, 0xffff, 0, "Siig CyberSerial (1-port) 16550", 0x10 }, { 0x131f, 0x2001, 0xffff, 0, "Siig CyberSerial (1-port) 16650", 0x10 }, { 0x131f, 0x2002, 0xffff, 0, "Siig CyberSerial (1-port) 16850", 0x10 }, { 0x135c, 0x0190, 0xffff, 0, "Quatech SSCLP-100", 0x18 }, { 0x135c, 0x01c0, 0xffff, 0, "Quatech SSCLP-200/300", 0x18 }, { 0x135e, 0x7101, 0xffff, 0, "Sealevel Systems Single Port RS-232/422/485/530", 0x18 }, { 0x1407, 0x0110, 0xffff, 0, "Lava Computer mfg DSerial-PCI Port A", 0x10 }, { 0x1407, 0x0111, 0xffff, 0, "Lava Computer mfg DSerial-PCI Port B", 0x10 }, { 0x1407, 0x0510, 0xffff, 0, "Lava SP Serial 550 PCI", 0x10 }, { 0x1409, 0x7168, 0x1409, 0x4025, "Timedia Technology Serial Port", 0x10, 8 * DEFAULT_RCLK }, { 0x1409, 0x7168, 0x1409, 0x4027, "Timedia Technology Serial Port", 0x10, 8 * DEFAULT_RCLK }, { 0x1409, 0x7168, 0x1409, 0x4028, "Timedia Technology Serial Port", 0x10, 8 * DEFAULT_RCLK }, { 0x1409, 0x7168, 0x1409, 0x5025, "Timedia Technology Serial Port", 0x10, 8 * DEFAULT_RCLK }, { 0x1409, 0x7168, 0x1409, 0x5027, "Timedia Technology Serial Port", 0x10, 8 * DEFAULT_RCLK }, { 0x1415, 0x950b, 0xffff, 0, "Oxford Semiconductor OXCB950 Cardbus 16950 UART", 0x10, 16384000 }, { 0x14e4, 0x4344, 0xffff, 0, "Sony Ericsson GC89 PC Card", 0x10}, { 0x151f, 0x0000, 0xffff, 0, "TOPIC Semiconductor TP560 56k modem", 0x10 }, { 0x1fd4, 0x1999, 0x1fd4, 0x0001, "Sunix SER5xxxx Serial Port", 0x10, 8 * DEFAULT_RCLK }, { 0x8086, 0x1c3d, 0xffff, 0, "Intel AMT - KT Controller", 0x10 }, { 0x8086, 0x1d3d, 0xffff, 0, "Intel C600/X79 Series Chipset KT Controller", 0x10 }, { 0x8086, 0x2a07, 0xffff, 0, "Intel AMT - PM965/GM965 KT Controller", 0x10 }, { 0x8086, 0x2e17, 0xffff, 0, "4 Series Chipset Serial KT Controller", 0x10 }, { 0x8086, 0x3b67, 0xffff, 0, "5 Series/3400 Series Chipset KT Controller", 0x10 }, { 0x8086, 0x8811, 0xffff, 0, "Intel EG20T Serial Port 0", 0x10 }, { 0x8086, 0x8812, 0xffff, 0, "Intel EG20T Serial Port 1", 0x10 }, { 0x8086, 0x8813, 0xffff, 0, "Intel EG20T Serial Port 2", 0x10 }, { 0x8086, 0x8814, 0xffff, 0, "Intel EG20T Serial Port 3", 0x10 }, { 0x8086, 0x8c3d, 0xffff, 0, "Intel Lynx Point KT Controller", 0x10 }, +{ 0x8086, 0x8cbd, 0xffff, 0, "Intel Wildcat Point KT Controller", 0x10 }, { 0x9710, 0x9820, 0x1000, 1, "NetMos NM9820 Serial Port", 0x10 }, { 0x9710, 0x9835, 0x1000, 1, "NetMos NM9835 Serial Port", 0x10 }, { 0x9710, 0x9865, 0xa000, 0x1000, "NetMos NM9865 Serial Port", 0x10 }, { 0x9710, 0x9900, 0xa000, 0x1000, "MosChip MCS9900 PCIe to Peripheral Controller", 0x10 }, { 0x9710, 0x9901, 0xa000, 0x1000, "MosChip MCS9901 PCIe to Peripheral Controller", 0x10 }, { 0x9710, 0x9904, 0xa000, 0x1000, "MosChip MCS9904 PCIe to Peripheral Controller", 0x10 }, { 0x9710, 0x9922, 0xffff, 0, "MosChip MCS9922 Multi I/O Controller", 0x10 }, { 0xdeaf, 0x9051, 0xffff, 0, "Middle Digital PC Weasel Serial Port", 0x10 }, { 0xffff, 0, 0xffff, 0, NULL, 0, 0} }; const static struct pci_id * uart_pci_match(device_t dev, const struct pci_id *id) { uint16_t device, subdev, subven, vendor; vendor = pci_get_vendor(dev); device = pci_get_device(dev); while (id->vendor != 0xffff && (id->vendor != vendor || id->device != device)) id++; if (id->vendor == 0xffff) return (NULL); if (id->subven == 0xffff) return (id); subven = pci_get_subvendor(dev); subdev = pci_get_subdevice(dev); while (id->vendor == vendor && id->device == device && (id->subven != subven || id->subdev != subdev)) id++; return ((id->vendor == vendor && id->device == device) ? id : NULL); } static int uart_pci_probe(device_t dev) { struct uart_softc *sc; const struct pci_id *id; int result; sc = device_get_softc(dev); id = uart_pci_match(dev, pci_ns8250_ids); if (id != NULL) { sc->sc_class = &uart_ns8250_class; goto match; } /* Add checks for non-ns8250 IDs here. */ return (ENXIO); match: result = uart_bus_probe(dev, 0, id->rclk, id->rid, 0); /* Bail out on error. */ if (result > 0) return (result); /* Set/override the device description. */ if (id->desc) device_set_desc(dev, id->desc); return (result); } DRIVER_MODULE(uart, pci, uart_pci_driver, uart_devclass, NULL, NULL); Index: head/sys/dev/usb/controller/ehci_pci.c =================================================================== --- head/sys/dev/usb/controller/ehci_pci.c (revision 275100) +++ head/sys/dev/usb/controller/ehci_pci.c (revision 275101) @@ -1,575 +1,579 @@ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Lennart Augustsson (augustss@carlstedt.se) at * Carlstedt Research & Technology. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * USB Enhanced Host Controller Driver, a.k.a. USB 2.0 controller. * * The EHCI 1.0 spec can be found at * http://developer.intel.com/technology/usb/download/ehci-r10.pdf * and the USB 2.0 spec at * http://www.usb.org/developers/docs/usb_20.zip */ /* The low level controller code for EHCI has been split into * PCI probes and EHCI specific code. This was done to facilitate the * sharing of code between *BSD's */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "usb_if.h" #define PCI_EHCI_VENDORID_ACERLABS 0x10b9 #define PCI_EHCI_VENDORID_AMD 0x1022 #define PCI_EHCI_VENDORID_APPLE 0x106b #define PCI_EHCI_VENDORID_ATI 0x1002 #define PCI_EHCI_VENDORID_CMDTECH 0x1095 #define PCI_EHCI_VENDORID_INTEL 0x8086 #define PCI_EHCI_VENDORID_NEC 0x1033 #define PCI_EHCI_VENDORID_OPTI 0x1045 #define PCI_EHCI_VENDORID_PHILIPS 0x1131 #define PCI_EHCI_VENDORID_SIS 0x1039 #define PCI_EHCI_VENDORID_NVIDIA 0x12D2 #define PCI_EHCI_VENDORID_NVIDIA2 0x10DE #define PCI_EHCI_VENDORID_VIA 0x1106 static device_probe_t ehci_pci_probe; static device_attach_t ehci_pci_attach; static device_detach_t ehci_pci_detach; static usb_take_controller_t ehci_pci_take_controller; static const char * ehci_pci_match(device_t self) { uint32_t device_id = pci_get_devid(self); switch (device_id) { case 0x523910b9: return "ALi M5239 USB 2.0 controller"; case 0x10227463: return "AMD 8111 USB 2.0 controller"; case 0x20951022: return ("AMD CS5536 (Geode) USB 2.0 controller"); case 0x43451002: return "ATI SB200 USB 2.0 controller"; case 0x43731002: return "ATI SB400 USB 2.0 controller"; case 0x43961002: return ("AMD SB7x0/SB8x0/SB9x0 USB 2.0 controller"); case 0x0f348086: return ("Intel BayTrail USB 2.0 controller"); case 0x1d268086: return ("Intel Patsburg USB 2.0 controller"); case 0x1d2d8086: return ("Intel Patsburg USB 2.0 controller"); case 0x1e268086: return ("Intel Panther Point USB 2.0 controller"); case 0x1e2d8086: return ("Intel Panther Point USB 2.0 controller"); case 0x1f2c8086: return ("Intel Avoton USB 2.0 controller"); case 0x25ad8086: return "Intel 6300ESB USB 2.0 controller"; case 0x24cd8086: return "Intel 82801DB/L/M (ICH4) USB 2.0 controller"; case 0x24dd8086: return "Intel 82801EB/R (ICH5) USB 2.0 controller"; case 0x265c8086: return "Intel 82801FB (ICH6) USB 2.0 controller"; case 0x268c8086: return ("Intel 63XXESB USB 2.0 controller"); case 0x27cc8086: return "Intel 82801GB/R (ICH7) USB 2.0 controller"; case 0x28368086: return "Intel 82801H (ICH8) USB 2.0 controller USB2-A"; case 0x283a8086: return "Intel 82801H (ICH8) USB 2.0 controller USB2-B"; case 0x293a8086: return "Intel 82801I (ICH9) USB 2.0 controller"; case 0x293c8086: return "Intel 82801I (ICH9) USB 2.0 controller"; case 0x3a3a8086: return "Intel 82801JI (ICH10) USB 2.0 controller USB-A"; case 0x3a3c8086: return "Intel 82801JI (ICH10) USB 2.0 controller USB-B"; case 0x3b348086: return ("Intel PCH USB 2.0 controller USB-A"); case 0x3b3c8086: return ("Intel PCH USB 2.0 controller USB-B"); case 0x8c268086: return ("Intel Lynx Point USB 2.0 controller USB-A"); case 0x8c2d8086: return ("Intel Lynx Point USB 2.0 controller USB-B"); + case 0x8ca68086: + return ("Intel Wildcat Point USB 2.0 controller USB-A"); + case 0x8cad8086: + return ("Intel Wildcat Point USB 2.0 controller USB-B"); case 0x00e01033: return ("NEC uPD 720100 USB 2.0 controller"); case 0x006810de: return "NVIDIA nForce2 USB 2.0 controller"; case 0x008810de: return "NVIDIA nForce2 Ultra 400 USB 2.0 controller"; case 0x00d810de: return "NVIDIA nForce3 USB 2.0 controller"; case 0x00e810de: return "NVIDIA nForce3 250 USB 2.0 controller"; case 0x005b10de: return "NVIDIA nForce CK804 USB 2.0 controller"; case 0x036d10de: return "NVIDIA nForce MCP55 USB 2.0 controller"; case 0x03f210de: return "NVIDIA nForce MCP61 USB 2.0 controller"; case 0x0aa610de: return "NVIDIA nForce MCP79 USB 2.0 controller"; case 0x0aa910de: return "NVIDIA nForce MCP79 USB 2.0 controller"; case 0x0aaa10de: return "NVIDIA nForce MCP79 USB 2.0 controller"; case 0x15621131: return "Philips ISP156x USB 2.0 controller"; case 0x31041106: return ("VIA VT6202 USB 2.0 controller"); default: break; } if ((pci_get_class(self) == PCIC_SERIALBUS) && (pci_get_subclass(self) == PCIS_SERIALBUS_USB) && (pci_get_progif(self) == PCI_INTERFACE_EHCI)) { return ("EHCI (generic) USB 2.0 controller"); } return (NULL); /* dunno */ } static int ehci_pci_probe(device_t self) { const char *desc = ehci_pci_match(self); if (desc) { device_set_desc(self, desc); return (0); } else { return (ENXIO); } } static void ehci_pci_ati_quirk(device_t self, uint8_t is_sb700) { device_t smbdev; uint32_t val; if (is_sb700) { /* Lookup SMBUS PCI device */ smbdev = pci_find_device(PCI_EHCI_VENDORID_ATI, 0x4385); if (smbdev == NULL) return; val = pci_get_revid(smbdev); if (val != 0x3a && val != 0x3b) return; } /* * Note: this bit is described as reserved in SB700 * Register Reference Guide. */ val = pci_read_config(self, 0x53, 1); if (!(val & 0x8)) { val |= 0x8; pci_write_config(self, 0x53, val, 1); device_printf(self, "AMD SB600/700 quirk applied\n"); } } static void ehci_pci_via_quirk(device_t self) { uint32_t val; if ((pci_get_device(self) == 0x3104) && ((pci_get_revid(self) & 0xf0) == 0x60)) { /* Correct schedule sleep time to 10us */ val = pci_read_config(self, 0x4b, 1); if (val & 0x20) return; val |= 0x20; pci_write_config(self, 0x4b, val, 1); device_printf(self, "VIA-quirk applied\n"); } } static int ehci_pci_attach(device_t self) { ehci_softc_t *sc = device_get_softc(self); int err; int rid; /* initialise some bus fields */ sc->sc_bus.parent = self; sc->sc_bus.devices = sc->sc_devices; sc->sc_bus.devices_max = EHCI_MAX_DEVICES; /* get all DMA memory */ if (usb_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) { return (ENOMEM); } pci_enable_busmaster(self); switch (pci_read_config(self, PCI_USBREV, 1) & PCI_USB_REV_MASK) { case PCI_USB_REV_PRE_1_0: case PCI_USB_REV_1_0: case PCI_USB_REV_1_1: /* * NOTE: some EHCI USB controllers have the wrong USB * revision number. It appears those controllers are * fully compliant so we just ignore this value in * some common cases. */ device_printf(self, "pre-2.0 USB revision (ignored)\n"); /* fallthrough */ case PCI_USB_REV_2_0: break; default: /* Quirk for Parallels Desktop 4.0 */ device_printf(self, "USB revision is unknown. Assuming v2.0.\n"); break; } rid = PCI_CBMEM; sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->sc_io_res) { device_printf(self, "Could not map memory\n"); goto error; } sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); sc->sc_io_size = rman_get_size(sc->sc_io_res); rid = 0; sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); if (sc->sc_irq_res == NULL) { device_printf(self, "Could not allocate irq\n"); goto error; } sc->sc_bus.bdev = device_add_child(self, "usbus", -1); if (!sc->sc_bus.bdev) { device_printf(self, "Could not add USB device\n"); goto error; } device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); /* * ehci_pci_match will never return NULL if ehci_pci_probe * succeeded */ device_set_desc(sc->sc_bus.bdev, ehci_pci_match(self)); switch (pci_get_vendor(self)) { case PCI_EHCI_VENDORID_ACERLABS: sprintf(sc->sc_vendor, "AcerLabs"); break; case PCI_EHCI_VENDORID_AMD: sprintf(sc->sc_vendor, "AMD"); break; case PCI_EHCI_VENDORID_APPLE: sprintf(sc->sc_vendor, "Apple"); break; case PCI_EHCI_VENDORID_ATI: sprintf(sc->sc_vendor, "ATI"); break; case PCI_EHCI_VENDORID_CMDTECH: sprintf(sc->sc_vendor, "CMDTECH"); break; case PCI_EHCI_VENDORID_INTEL: sprintf(sc->sc_vendor, "Intel"); break; case PCI_EHCI_VENDORID_NEC: sprintf(sc->sc_vendor, "NEC"); break; case PCI_EHCI_VENDORID_OPTI: sprintf(sc->sc_vendor, "OPTi"); break; case PCI_EHCI_VENDORID_PHILIPS: sprintf(sc->sc_vendor, "Philips"); break; case PCI_EHCI_VENDORID_SIS: sprintf(sc->sc_vendor, "SiS"); break; case PCI_EHCI_VENDORID_NVIDIA: case PCI_EHCI_VENDORID_NVIDIA2: sprintf(sc->sc_vendor, "nVidia"); break; case PCI_EHCI_VENDORID_VIA: sprintf(sc->sc_vendor, "VIA"); break; default: if (bootverbose) device_printf(self, "(New EHCI DeviceId=0x%08x)\n", pci_get_devid(self)); sprintf(sc->sc_vendor, "(0x%04x)", pci_get_vendor(self)); } #if (__FreeBSD_version >= 700031) err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); #else err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); #endif if (err) { device_printf(self, "Could not setup irq, %d\n", err); sc->sc_intr_hdl = NULL; goto error; } ehci_pci_take_controller(self); /* Undocumented quirks taken from Linux */ switch (pci_get_vendor(self)) { case PCI_EHCI_VENDORID_ATI: /* SB600 and SB700 EHCI quirk */ switch (pci_get_device(self)) { case 0x4386: ehci_pci_ati_quirk(self, 0); break; case 0x4396: ehci_pci_ati_quirk(self, 1); break; default: break; } break; case PCI_EHCI_VENDORID_VIA: ehci_pci_via_quirk(self); break; default: break; } /* Dropped interrupts workaround */ switch (pci_get_vendor(self)) { case PCI_EHCI_VENDORID_ATI: case PCI_EHCI_VENDORID_VIA: sc->sc_flags |= EHCI_SCFLG_LOSTINTRBUG; if (bootverbose) device_printf(self, "Dropped interrupts workaround enabled\n"); break; default: break; } /* Doorbell feature workaround */ switch (pci_get_vendor(self)) { case PCI_EHCI_VENDORID_NVIDIA: case PCI_EHCI_VENDORID_NVIDIA2: sc->sc_flags |= EHCI_SCFLG_IAADBUG; if (bootverbose) device_printf(self, "Doorbell workaround enabled\n"); break; default: break; } err = ehci_init(sc); if (!err) { err = device_probe_and_attach(sc->sc_bus.bdev); } if (err) { device_printf(self, "USB init failed err=%d\n", err); goto error; } return (0); error: ehci_pci_detach(self); return (ENXIO); } static int ehci_pci_detach(device_t self) { ehci_softc_t *sc = device_get_softc(self); device_t bdev; if (sc->sc_bus.bdev) { bdev = sc->sc_bus.bdev; device_detach(bdev); device_delete_child(self, bdev); } /* during module unload there are lots of children leftover */ device_delete_children(self); pci_disable_busmaster(self); if (sc->sc_irq_res && sc->sc_intr_hdl) { /* * only call ehci_detach() after ehci_init() */ ehci_detach(sc); int err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); if (err) /* XXX or should we panic? */ device_printf(self, "Could not tear down irq, %d\n", err); sc->sc_intr_hdl = NULL; } if (sc->sc_irq_res) { bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); sc->sc_irq_res = NULL; } if (sc->sc_io_res) { bus_release_resource(self, SYS_RES_MEMORY, PCI_CBMEM, sc->sc_io_res); sc->sc_io_res = NULL; } usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); return (0); } static int ehci_pci_take_controller(device_t self) { ehci_softc_t *sc = device_get_softc(self); uint32_t cparams; uint32_t eec; uint16_t to; uint8_t eecp; uint8_t bios_sem; cparams = EREAD4(sc, EHCI_HCCPARAMS); /* Synchronise with the BIOS if it owns the controller. */ for (eecp = EHCI_HCC_EECP(cparams); eecp != 0; eecp = EHCI_EECP_NEXT(eec)) { eec = pci_read_config(self, eecp, 4); if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP) { continue; } bios_sem = pci_read_config(self, eecp + EHCI_LEGSUP_BIOS_SEM, 1); if (bios_sem == 0) { continue; } device_printf(sc->sc_bus.bdev, "waiting for BIOS " "to give up control\n"); pci_write_config(self, eecp + EHCI_LEGSUP_OS_SEM, 1, 1); to = 500; while (1) { bios_sem = pci_read_config(self, eecp + EHCI_LEGSUP_BIOS_SEM, 1); if (bios_sem == 0) break; if (--to == 0) { device_printf(sc->sc_bus.bdev, "timed out waiting for BIOS\n"); break; } usb_pause_mtx(NULL, hz / 100); /* wait 10ms */ } } return (0); } static device_method_t ehci_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ehci_pci_probe), DEVMETHOD(device_attach, ehci_pci_attach), DEVMETHOD(device_detach, ehci_pci_detach), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(usb_take_controller, ehci_pci_take_controller), DEVMETHOD_END }; static driver_t ehci_driver = { .name = "ehci", .methods = ehci_pci_methods, .size = sizeof(struct ehci_softc), }; static devclass_t ehci_devclass; DRIVER_MODULE(ehci, pci, ehci_driver, ehci_devclass, 0, 0); MODULE_DEPEND(ehci, usb, 1, 1, 1); Index: head/sys/dev/usb/controller/xhci_pci.c =================================================================== --- head/sys/dev/usb/controller/xhci_pci.c (revision 275100) +++ head/sys/dev/usb/controller/xhci_pci.c (revision 275101) @@ -1,369 +1,371 @@ /*- * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "usb_if.h" static device_probe_t xhci_pci_probe; static device_attach_t xhci_pci_attach; static device_detach_t xhci_pci_detach; static usb_take_controller_t xhci_pci_take_controller; static device_method_t xhci_device_methods[] = { /* device interface */ DEVMETHOD(device_probe, xhci_pci_probe), DEVMETHOD(device_attach, xhci_pci_attach), DEVMETHOD(device_detach, xhci_pci_detach), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(usb_take_controller, xhci_pci_take_controller), DEVMETHOD_END }; static driver_t xhci_driver = { .name = "xhci", .methods = xhci_device_methods, .size = sizeof(struct xhci_softc), }; static devclass_t xhci_devclass; DRIVER_MODULE(xhci, pci, xhci_driver, xhci_devclass, 0, 0); MODULE_DEPEND(xhci, usb, 1, 1, 1); static const char * xhci_pci_match(device_t self) { uint32_t device_id = pci_get_devid(self); switch (device_id) { case 0x01941033: return ("NEC uPD720200 USB 3.0 controller"); case 0x10421b21: return ("ASMedia ASM1042 USB 3.0 controller"); case 0x0f358086: return ("Intel Intel BayTrail USB 3.0 controller"); case 0x9c318086: case 0x1e318086: return ("Intel Panther Point USB 3.0 controller"); case 0x8c318086: return ("Intel Lynx Point USB 3.0 controller"); + case 0x8cb18086: + return ("Intel Wildcat Point USB 3.0 controller"); default: break; } if ((pci_get_class(self) == PCIC_SERIALBUS) && (pci_get_subclass(self) == PCIS_SERIALBUS_USB) && (pci_get_progif(self) == PCIP_SERIALBUS_USB_XHCI)) { return ("XHCI (generic) USB 3.0 controller"); } return (NULL); /* dunno */ } static int xhci_pci_probe(device_t self) { const char *desc = xhci_pci_match(self); if (desc) { device_set_desc(self, desc); return (0); } else { return (ENXIO); } } static int xhci_use_msi = 1; TUNABLE_INT("hw.usb.xhci.msi", &xhci_use_msi); static void xhci_interrupt_poll(void *_sc) { struct xhci_softc *sc = _sc; USB_BUS_UNLOCK(&sc->sc_bus); xhci_interrupt(sc); USB_BUS_LOCK(&sc->sc_bus); usb_callout_reset(&sc->sc_callout, 1, (void *)&xhci_interrupt_poll, sc); } static int xhci_pci_port_route(device_t self, uint32_t set, uint32_t clear) { uint32_t temp; uint32_t usb3_mask; uint32_t usb2_mask; temp = pci_read_config(self, PCI_XHCI_INTEL_USB3_PSSEN, 4) | pci_read_config(self, PCI_XHCI_INTEL_XUSB2PR, 4); temp |= set; temp &= ~clear; /* Don't set bits which the hardware doesn't support */ usb3_mask = pci_read_config(self, PCI_XHCI_INTEL_USB3PRM, 4); usb2_mask = pci_read_config(self, PCI_XHCI_INTEL_USB2PRM, 4); pci_write_config(self, PCI_XHCI_INTEL_USB3_PSSEN, temp & usb3_mask, 4); pci_write_config(self, PCI_XHCI_INTEL_XUSB2PR, temp & usb2_mask, 4); device_printf(self, "Port routing mask set to 0x%08x\n", temp); return (0); } static int xhci_pci_attach(device_t self) { struct xhci_softc *sc = device_get_softc(self); int count, err, rid; /* XXX check for 64-bit capability */ if (xhci_init(sc, self)) { device_printf(self, "Could not initialize softc\n"); goto error; } pci_enable_busmaster(self); rid = PCI_XHCI_CBMEM; sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->sc_io_res) { device_printf(self, "Could not map memory\n"); goto error; } sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); sc->sc_io_size = rman_get_size(sc->sc_io_res); usb_callout_init_mtx(&sc->sc_callout, &sc->sc_bus.bus_mtx, 0); sc->sc_irq_rid = 0; if (xhci_use_msi) { count = pci_msi_count(self); if (count >= 1) { count = 1; if (pci_alloc_msi(self, &count) == 0) { if (bootverbose) device_printf(self, "MSI enabled\n"); sc->sc_irq_rid = 1; } } } sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &sc->sc_irq_rid, RF_SHAREABLE | RF_ACTIVE); if (sc->sc_irq_res == NULL) { device_printf(self, "Could not allocate IRQ\n"); /* goto error; FALLTHROUGH - use polling */ } sc->sc_bus.bdev = device_add_child(self, "usbus", -1); if (sc->sc_bus.bdev == NULL) { device_printf(self, "Could not add USB device\n"); goto error; } device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); sprintf(sc->sc_vendor, "0x%04x", pci_get_vendor(self)); if (sc->sc_irq_res != NULL) { err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, NULL, (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl); if (err != 0) { device_printf(self, "Could not setup IRQ, err=%d\n", err); sc->sc_intr_hdl = NULL; } } if (sc->sc_irq_res == NULL || sc->sc_intr_hdl == NULL || xhci_use_polling() != 0) { device_printf(self, "Interrupt polling at %dHz\n", hz); USB_BUS_LOCK(&sc->sc_bus); xhci_interrupt_poll(sc); USB_BUS_UNLOCK(&sc->sc_bus); } /* On Intel chipsets reroute ports from EHCI to XHCI controller. */ switch (pci_get_devid(self)) { case 0x0f358086: /* BayTrail */ case 0x9c318086: /* Panther Point */ case 0x1e318086: /* Panther Point */ case 0x8c318086: /* Lynx Point */ sc->sc_port_route = &xhci_pci_port_route; sc->sc_imod_default = XHCI_IMOD_DEFAULT_LP; break; default: break; } xhci_pci_take_controller(self); err = xhci_halt_controller(sc); if (err == 0) err = xhci_start_controller(sc); if (err == 0) err = device_probe_and_attach(sc->sc_bus.bdev); if (err) { device_printf(self, "XHCI halt/start/probe failed err=%d\n", err); goto error; } return (0); error: xhci_pci_detach(self); return (ENXIO); } static int xhci_pci_detach(device_t self) { struct xhci_softc *sc = device_get_softc(self); device_t bdev; if (sc->sc_bus.bdev != NULL) { bdev = sc->sc_bus.bdev; device_detach(bdev); device_delete_child(self, bdev); } /* during module unload there are lots of children leftover */ device_delete_children(self); if (sc->sc_io_res) { usb_callout_drain(&sc->sc_callout); xhci_halt_controller(sc); } pci_disable_busmaster(self); if (sc->sc_irq_res && sc->sc_intr_hdl) { bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); sc->sc_intr_hdl = NULL; } if (sc->sc_irq_res) { if (sc->sc_irq_rid == 1) pci_release_msi(self); bus_release_resource(self, SYS_RES_IRQ, sc->sc_irq_rid, sc->sc_irq_res); sc->sc_irq_res = NULL; } if (sc->sc_io_res) { bus_release_resource(self, SYS_RES_MEMORY, PCI_XHCI_CBMEM, sc->sc_io_res); sc->sc_io_res = NULL; } xhci_uninit(sc); return (0); } static int xhci_pci_take_controller(device_t self) { struct xhci_softc *sc = device_get_softc(self); uint32_t cparams; uint32_t eecp; uint32_t eec; uint16_t to; uint8_t bios_sem; cparams = XREAD4(sc, capa, XHCI_HCSPARAMS0); eec = -1; /* Synchronise with the BIOS if it owns the controller. */ for (eecp = XHCI_HCS0_XECP(cparams) << 2; eecp != 0 && XHCI_XECP_NEXT(eec); eecp += XHCI_XECP_NEXT(eec) << 2) { eec = XREAD4(sc, capa, eecp); if (XHCI_XECP_ID(eec) != XHCI_ID_USB_LEGACY) continue; bios_sem = XREAD1(sc, capa, eecp + XHCI_XECP_BIOS_SEM); if (bios_sem == 0) continue; device_printf(sc->sc_bus.bdev, "waiting for BIOS " "to give up control\n"); XWRITE1(sc, capa, eecp + XHCI_XECP_OS_SEM, 1); to = 500; while (1) { bios_sem = XREAD1(sc, capa, eecp + XHCI_XECP_BIOS_SEM); if (bios_sem == 0) break; if (--to == 0) { device_printf(sc->sc_bus.bdev, "timed out waiting for BIOS\n"); break; } usb_pause_mtx(NULL, hz / 100); /* wait 10ms */ } } return (0); }