1*b95d480dSabs /* $NetBSD: ahcisata_pci.c,v 1.71 2023/10/10 16:46:56 abs Exp $ */
2920d7a6aSbouyer
3920d7a6aSbouyer /*
4920d7a6aSbouyer * Copyright (c) 2006 Manuel Bouyer.
5920d7a6aSbouyer *
6920d7a6aSbouyer * Redistribution and use in source and binary forms, with or without
7920d7a6aSbouyer * modification, are permitted provided that the following conditions
8920d7a6aSbouyer * are met:
9920d7a6aSbouyer * 1. Redistributions of source code must retain the above copyright
10920d7a6aSbouyer * notice, this list of conditions and the following disclaimer.
11920d7a6aSbouyer * 2. Redistributions in binary form must reproduce the above copyright
12920d7a6aSbouyer * notice, this list of conditions and the following disclaimer in the
13920d7a6aSbouyer * documentation and/or other materials provided with the distribution.
14920d7a6aSbouyer *
15920d7a6aSbouyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16920d7a6aSbouyer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17920d7a6aSbouyer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18920d7a6aSbouyer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19920d7a6aSbouyer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20920d7a6aSbouyer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21920d7a6aSbouyer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22920d7a6aSbouyer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23920d7a6aSbouyer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24920d7a6aSbouyer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25920d7a6aSbouyer *
26920d7a6aSbouyer */
27920d7a6aSbouyer
28920d7a6aSbouyer #include <sys/cdefs.h>
29*b95d480dSabs __KERNEL_RCSID(0, "$NetBSD: ahcisata_pci.c,v 1.71 2023/10/10 16:46:56 abs Exp $");
304374f2dbSskrll
314374f2dbSskrll #ifdef _KERNEL_OPT
324374f2dbSskrll #include "opt_ahcisata_pci.h"
334374f2dbSskrll #endif
34920d7a6aSbouyer
35920d7a6aSbouyer #include <sys/types.h>
3683226ad3Sjdolecek #include <sys/kmem.h>
37920d7a6aSbouyer #include <sys/param.h>
38920d7a6aSbouyer #include <sys/kernel.h>
39920d7a6aSbouyer #include <sys/systm.h>
40920d7a6aSbouyer #include <sys/disklabel.h>
414c1d81b2Sjmcneill #include <sys/pmf.h>
42920d7a6aSbouyer
43920d7a6aSbouyer #include <dev/pci/pcivar.h>
44920d7a6aSbouyer #include <dev/pci/pcidevs.h>
45920d7a6aSbouyer #include <dev/pci/pciidereg.h>
46920d7a6aSbouyer #include <dev/pci/pciidevar.h>
47920d7a6aSbouyer #include <dev/ic/ahcisatavar.h>
48920d7a6aSbouyer
495630ecd4Sjakllsch struct ahci_pci_quirk {
505630ecd4Sjakllsch pci_vendor_id_t vendor; /* Vendor ID */
515630ecd4Sjakllsch pci_product_id_t product; /* Product ID */
525a3c59bfSbouyer int quirks; /* quirks; same as sc_ahci_quirks */
535630ecd4Sjakllsch };
54f6bd05d8Sdillo
555630ecd4Sjakllsch static const struct ahci_pci_quirk ahci_pci_quirks[] = {
56f6bd05d8Sdillo { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_SATA,
578539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
58c963cec0Sdholland { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_SATA2,
598539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
60c963cec0Sdholland { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_SATA3,
618539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
62c963cec0Sdholland { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_SATA4,
638539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
648539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_AHCI_1,
658539c8f3Sbouyer AHCI_QUIRK_BADPMP },
668539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_AHCI_2,
678539c8f3Sbouyer AHCI_QUIRK_BADPMP },
688539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_AHCI_3,
698539c8f3Sbouyer AHCI_QUIRK_BADPMP },
708539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_AHCI_4,
718539c8f3Sbouyer AHCI_QUIRK_BADPMP },
72f6bd05d8Sdillo { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_SATA,
738539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
748539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_SATA2,
758539c8f3Sbouyer AHCI_QUIRK_BADPMP },
768539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_SATA3,
778539c8f3Sbouyer AHCI_QUIRK_BADPMP },
788539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_SATA4,
798539c8f3Sbouyer AHCI_QUIRK_BADPMP },
808539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_AHCI_1,
818539c8f3Sbouyer AHCI_QUIRK_BADPMP },
828539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_AHCI_2,
838539c8f3Sbouyer AHCI_QUIRK_BADPMP },
848539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_AHCI_3,
858539c8f3Sbouyer AHCI_QUIRK_BADPMP },
868539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_AHCI_4,
878539c8f3Sbouyer AHCI_QUIRK_BADPMP },
888539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_AHCI_5,
898539c8f3Sbouyer AHCI_QUIRK_BADPMP },
908539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_AHCI_6,
918539c8f3Sbouyer AHCI_QUIRK_BADPMP },
928539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_AHCI_7,
938539c8f3Sbouyer AHCI_QUIRK_BADPMP },
948539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_AHCI_8,
958539c8f3Sbouyer AHCI_QUIRK_BADPMP },
96e123b7f4Stron { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_1,
978539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
988539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_2,
998539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1008539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_3,
1018539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1028539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_4,
1038539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1048539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_5,
1058539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1068539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_6,
1078539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1088539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_7,
1098539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1108539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_8,
1118539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1128539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_9,
1138539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1148539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_10,
1158539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1168539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_11,
1178539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1188539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_12,
1198539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1203c583378Sjmcneill { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_1,
1218539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
1223c583378Sjmcneill { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_2,
1238539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
1243c583378Sjmcneill { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_3,
1258539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
1263c583378Sjmcneill { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_4,
1278539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
1283c583378Sjmcneill { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_5,
1298539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
1303c583378Sjmcneill { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_6,
1318539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
1323c583378Sjmcneill { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_7,
1338539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
1343c583378Sjmcneill { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_8,
1358539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
1363c583378Sjmcneill { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_9,
1378539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
1383c583378Sjmcneill { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_10,
1398539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
1403c583378Sjmcneill { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_11,
1418539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
1423c583378Sjmcneill { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_12,
1438539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
1448539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_1,
1458539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1468539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_2,
1478539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1488539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_3,
1498539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1508539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_4,
1518539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1528539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_5,
1538539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1548539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_6,
1558539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1568539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_7,
1578539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1588539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_8,
1598539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1608539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_9,
1618539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1628539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_10,
1638539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1648539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_11,
1658539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1668539c8f3Sbouyer { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_12,
1678539c8f3Sbouyer AHCI_QUIRK_BADPMP },
16812a7a4f8Smatt { PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M5288,
16912a7a4f8Smatt AHCI_PCI_QUIRK_FORCE },
170535480ccScegger { PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_88SE6121,
1718539c8f3Sbouyer AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
1728539c8f3Sbouyer { PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_88SE6145,
1738539c8f3Sbouyer AHCI_QUIRK_BADPMP },
174a9a7d73cSmsaitoh { PCI_VENDOR_MARVELL2, PCI_PRODUCT_MARVELL2_88SE91XX,
175ae79d560Sjakllsch AHCI_PCI_QUIRK_FORCE },
17695ea24f1Sjakllsch /* ATI SB600 AHCI 64-bit DMA only works on some boards/BIOSes */
17795ea24f1Sjakllsch { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB600_SATA_1,
1780361294bSsimonb AHCI_PCI_QUIRK_BAD64 | AHCI_QUIRK_BADPMP | AHCI_QUIRK_BADNCQ },
1798539c8f3Sbouyer { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB700_SATA_AHCI,
1800361294bSsimonb AHCI_QUIRK_BADPMP | AHCI_QUIRK_BADNCQ },
1818539c8f3Sbouyer { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB700_SATA_RAID,
1820361294bSsimonb AHCI_QUIRK_BADPMP | AHCI_QUIRK_BADNCQ },
1838539c8f3Sbouyer { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB700_SATA_RAID5,
1840361294bSsimonb AHCI_QUIRK_BADPMP | AHCI_QUIRK_BADNCQ },
1858539c8f3Sbouyer { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB700_SATA_AHCI2,
1860361294bSsimonb AHCI_QUIRK_BADPMP | AHCI_QUIRK_BADNCQ },
187329fe36aSmsaitoh { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB700_SATA_STORAGE,
1880361294bSsimonb AHCI_QUIRK_BADPMP | AHCI_QUIRK_BADNCQ },
1898539c8f3Sbouyer { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237R_SATA,
1908539c8f3Sbouyer AHCI_QUIRK_BADPMP },
1918539c8f3Sbouyer { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8251_SATA,
1928539c8f3Sbouyer AHCI_QUIRK_BADPMP },
193d37307fcSmatt { PCI_VENDOR_ASMEDIA, PCI_PRODUCT_ASMEDIA_ASM1061_01,
194d37307fcSmatt AHCI_PCI_QUIRK_FORCE },
195d37307fcSmatt { PCI_VENDOR_ASMEDIA, PCI_PRODUCT_ASMEDIA_ASM1061_02,
196d37307fcSmatt AHCI_PCI_QUIRK_FORCE },
197d37307fcSmatt { PCI_VENDOR_ASMEDIA, PCI_PRODUCT_ASMEDIA_ASM1061_11,
198d37307fcSmatt AHCI_PCI_QUIRK_FORCE },
199d37307fcSmatt { PCI_VENDOR_ASMEDIA, PCI_PRODUCT_ASMEDIA_ASM1061_12,
200ef412e3dSabs AHCI_PCI_QUIRK_FORCE },
201*b95d480dSabs { PCI_VENDOR_ASMEDIA, PCI_PRODUCT_ASMEDIA_ASM1062_JMB575,
202*b95d480dSabs AHCI_PCI_QUIRK_FORCE },
20373e2364eSjdolecek { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_HUDSON_SATA,
20473e2364eSjdolecek AHCI_PCI_QUIRK_FORCE },
205062be89dSjdolecek { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_HUDSON_SATA_AHCI,
20692aa3d3dSjdolecek AHCI_QUIRK_BADPMP },
2079009bd65Srin { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801JI_SATA_AHCI,
2089009bd65Srin AHCI_QUIRK_BADPMP },
209f6bd05d8Sdillo };
210f6bd05d8Sdillo
2114c1d81b2Sjmcneill struct ahci_pci_softc {
2127aa6248cScube struct ahci_softc ah_sc;
2134c1d81b2Sjmcneill pci_chipset_tag_t sc_pc;
2144c1d81b2Sjmcneill pcitag_t sc_pcitag;
215830d6e2eSjdolecek pci_intr_handle_t *sc_pihp;
21683226ad3Sjdolecek int sc_nintr;
21783226ad3Sjdolecek void **sc_ih;
2184c1d81b2Sjmcneill };
2194c1d81b2Sjmcneill
2208539c8f3Sbouyer static int ahci_pci_has_quirk(pci_vendor_id_t, pci_product_id_t);
2217aa6248cScube static int ahci_pci_match(device_t, cfdata_t, void *);
2227aa6248cScube static void ahci_pci_attach(device_t, device_t, void *);
2235630ecd4Sjakllsch static int ahci_pci_detach(device_t, int);
224654326faSjdolecek static void ahci_pci_childdetached(device_t, device_t);
225c1b390d4Sdyoung static bool ahci_pci_resume(device_t, const pmf_qual_t *);
226920d7a6aSbouyer
2274c1d81b2Sjmcneill
228654326faSjdolecek CFATTACH_DECL3_NEW(ahcisata_pci, sizeof(struct ahci_pci_softc),
229654326faSjdolecek ahci_pci_match, ahci_pci_attach, ahci_pci_detach, NULL,
230654326faSjdolecek NULL, ahci_pci_childdetached, DVF_DETACH_SHUTDOWN);
2315630ecd4Sjakllsch
2328fa4dc6bSskrll #define AHCI_PCI_ABAR_CAVIUM 0x10
2338fa4dc6bSskrll
2348539c8f3Sbouyer static int
ahci_pci_has_quirk(pci_vendor_id_t vendor,pci_product_id_t product)2358539c8f3Sbouyer ahci_pci_has_quirk(pci_vendor_id_t vendor, pci_product_id_t product)
2365630ecd4Sjakllsch {
2375630ecd4Sjakllsch int i;
2385630ecd4Sjakllsch
2395630ecd4Sjakllsch for (i = 0; i < __arraycount(ahci_pci_quirks); i++)
2405630ecd4Sjakllsch if (vendor == ahci_pci_quirks[i].vendor &&
2415630ecd4Sjakllsch product == ahci_pci_quirks[i].product)
2428539c8f3Sbouyer return ahci_pci_quirks[i].quirks;
2438539c8f3Sbouyer return 0;
2445630ecd4Sjakllsch }
245920d7a6aSbouyer
246920d7a6aSbouyer static int
ahci_pci_abar(struct pci_attach_args * pa)2478fa4dc6bSskrll ahci_pci_abar(struct pci_attach_args *pa)
2488fa4dc6bSskrll {
2498fa4dc6bSskrll if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_CAVIUM) {
2508fa4dc6bSskrll if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_CAVIUM_THUNDERX_AHCI ||
2518fa4dc6bSskrll PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_CAVIUM_THUNDERX_RAID) {
2528fa4dc6bSskrll return AHCI_PCI_ABAR_CAVIUM;
2538fa4dc6bSskrll }
2548fa4dc6bSskrll }
2558fa4dc6bSskrll
2568fa4dc6bSskrll return AHCI_PCI_ABAR;
2578fa4dc6bSskrll }
2588fa4dc6bSskrll
2598fa4dc6bSskrll
2608fa4dc6bSskrll static int
ahci_pci_match(device_t parent,cfdata_t match,void * aux)2617aa6248cScube ahci_pci_match(device_t parent, cfdata_t match, void *aux)
262920d7a6aSbouyer {
263920d7a6aSbouyer struct pci_attach_args *pa = aux;
264920d7a6aSbouyer bus_space_tag_t regt;
265920d7a6aSbouyer bus_space_handle_t regh;
266920d7a6aSbouyer bus_size_t size;
267920d7a6aSbouyer int ret = 0;
2685630ecd4Sjakllsch bool force;
269920d7a6aSbouyer
2708539c8f3Sbouyer force = ((ahci_pci_has_quirk( PCI_VENDOR(pa->pa_id),
2718539c8f3Sbouyer PCI_PRODUCT(pa->pa_id)) & AHCI_PCI_QUIRK_FORCE) != 0);
272f6bd05d8Sdillo
273f6bd05d8Sdillo /* if wrong class and not forced by quirks, don't match */
274f6bd05d8Sdillo if ((PCI_CLASS(pa->pa_class) != PCI_CLASS_MASS_STORAGE ||
275f6bd05d8Sdillo ((PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_MASS_STORAGE_SATA ||
276f6bd05d8Sdillo PCI_INTERFACE(pa->pa_class) != PCI_INTERFACE_SATA_AHCI) &&
277f6bd05d8Sdillo PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_MASS_STORAGE_RAID)) &&
2785630ecd4Sjakllsch (force == false))
279f6bd05d8Sdillo return 0;
280f6bd05d8Sdillo
2818fa4dc6bSskrll int bar = ahci_pci_abar(pa);
2828fa4dc6bSskrll pcireg_t memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, bar);
2838fa4dc6bSskrll if (pci_mapreg_map(pa, bar, memtype, 0, ®t, ®h, NULL, &size) != 0)
28449c4d911Sjnemeth return 0;
285920d7a6aSbouyer
286f6bd05d8Sdillo if ((PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_SATA &&
287f6bd05d8Sdillo PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_SATA_AHCI) ||
2885630ecd4Sjakllsch (bus_space_read_4(regt, regh, AHCI_GHC) & AHCI_GHC_AE) ||
2895630ecd4Sjakllsch (force == true))
290f6bd05d8Sdillo ret = 3;
291f6bd05d8Sdillo
292f6bd05d8Sdillo bus_space_unmap(regt, regh, size);
29349c4d911Sjnemeth return ret;
294920d7a6aSbouyer }
295920d7a6aSbouyer
29683226ad3Sjdolecek static int
ahci_pci_intr_establish(struct ahci_softc * sc,int port)29783226ad3Sjdolecek ahci_pci_intr_establish(struct ahci_softc *sc, int port)
29883226ad3Sjdolecek {
29983226ad3Sjdolecek struct ahci_pci_softc *psc = (struct ahci_pci_softc *)sc;
30083226ad3Sjdolecek device_t self = sc->sc_atac.atac_dev;
30183226ad3Sjdolecek char intrbuf[PCI_INTRSTR_LEN];
30283226ad3Sjdolecek char intr_xname[INTRDEVNAMEBUF];
30383226ad3Sjdolecek const char *intrstr;
30483226ad3Sjdolecek int vec;
30583226ad3Sjdolecek int (*intr_handler)(void *);
30683226ad3Sjdolecek void *intr_arg;
30783226ad3Sjdolecek
30883226ad3Sjdolecek KASSERT(psc->sc_pihp != NULL);
30983226ad3Sjdolecek KASSERT(psc->sc_nintr > 0);
31083226ad3Sjdolecek
31183226ad3Sjdolecek snprintf(intr_xname, sizeof(intr_xname), "%s", device_xname(self));
31283226ad3Sjdolecek
31383226ad3Sjdolecek if (psc->sc_nintr == 1 || sc->sc_ghc_mrsm) {
31483226ad3Sjdolecek /* Only one interrupt, established on vector 0 */
31583226ad3Sjdolecek intr_handler = ahci_intr;
31683226ad3Sjdolecek intr_arg = sc;
31783226ad3Sjdolecek vec = 0;
31883226ad3Sjdolecek
31983226ad3Sjdolecek if (psc->sc_ih[vec] != NULL) {
32083226ad3Sjdolecek /* Already established, nothing more to do */
32183226ad3Sjdolecek goto out;
32283226ad3Sjdolecek }
32383226ad3Sjdolecek
32483226ad3Sjdolecek } else {
32583226ad3Sjdolecek /*
32683226ad3Sjdolecek * Theoretically AHCI device can have less MSI/MSI-X vectors
32783226ad3Sjdolecek * than supported ports. Hardware is allowed to revert
32883226ad3Sjdolecek * to single message MSI, but not required to do so.
32983226ad3Sjdolecek * So handle the case when it did not revert to single MSI.
33083226ad3Sjdolecek * In this case last available interrupt vector is used
33183226ad3Sjdolecek * for port == max vector, and all further ports.
33283226ad3Sjdolecek * This last vector must use the general interrupt handler,
33383226ad3Sjdolecek * since it needs to be able to handle several ports.
33483226ad3Sjdolecek * NOTE: such case was never actually observed yet
33583226ad3Sjdolecek */
33683226ad3Sjdolecek if (sc->sc_atac.atac_nchannels > psc->sc_nintr
33783226ad3Sjdolecek && port >= (psc->sc_nintr - 1)) {
33883226ad3Sjdolecek intr_handler = ahci_intr;
33983226ad3Sjdolecek intr_arg = sc;
34083226ad3Sjdolecek vec = psc->sc_nintr - 1;
34183226ad3Sjdolecek
34283226ad3Sjdolecek if (psc->sc_ih[vec] != NULL) {
34383226ad3Sjdolecek /* Already established, nothing more to do */
34483226ad3Sjdolecek goto out;
34583226ad3Sjdolecek }
34683226ad3Sjdolecek
34783226ad3Sjdolecek if (port == vec) {
34883226ad3Sjdolecek /* Print error once */
34983226ad3Sjdolecek aprint_error_dev(self,
350ff23aff6Sandvar "port %d independent interrupt vector not "
35183226ad3Sjdolecek "available, sharing with further ports",
35283226ad3Sjdolecek port);
35383226ad3Sjdolecek }
35483226ad3Sjdolecek } else {
35583226ad3Sjdolecek /* Vector according to port */
35683226ad3Sjdolecek KASSERT(port < psc->sc_nintr);
35783226ad3Sjdolecek KASSERT(psc->sc_ih[port] == NULL);
35883226ad3Sjdolecek intr_handler = ahci_intr_port;
35983226ad3Sjdolecek intr_arg = &sc->sc_channels[port];
36083226ad3Sjdolecek vec = port;
36183226ad3Sjdolecek
36283226ad3Sjdolecek snprintf(intr_xname, sizeof(intr_xname), "%s port%d",
36383226ad3Sjdolecek device_xname(self), port);
36483226ad3Sjdolecek }
36583226ad3Sjdolecek }
36683226ad3Sjdolecek
36783226ad3Sjdolecek intrstr = pci_intr_string(psc->sc_pc, psc->sc_pihp[vec], intrbuf,
36883226ad3Sjdolecek sizeof(intrbuf));
36983226ad3Sjdolecek psc->sc_ih[vec] = pci_intr_establish_xname(psc->sc_pc,
37083226ad3Sjdolecek psc->sc_pihp[vec], IPL_BIO, intr_handler, intr_arg, intr_xname);
371ff583840Sskrll if (psc->sc_ih[vec] == NULL) {
37283226ad3Sjdolecek aprint_error_dev(self, "couldn't establish interrupt");
37383226ad3Sjdolecek if (intrstr != NULL)
37483226ad3Sjdolecek aprint_error(" at %s", intrstr);
37583226ad3Sjdolecek aprint_error("\n");
37683226ad3Sjdolecek goto fail;
37783226ad3Sjdolecek }
37883226ad3Sjdolecek aprint_normal_dev(self, "interrupting at %s\n", intrstr);
37983226ad3Sjdolecek
38083226ad3Sjdolecek out:
38183226ad3Sjdolecek return 0;
38283226ad3Sjdolecek
38383226ad3Sjdolecek fail:
38483226ad3Sjdolecek return EAGAIN;
38583226ad3Sjdolecek }
38683226ad3Sjdolecek
387920d7a6aSbouyer static void
ahci_pci_attach(device_t parent,device_t self,void * aux)3887aa6248cScube ahci_pci_attach(device_t parent, device_t self, void *aux)
389920d7a6aSbouyer {
390920d7a6aSbouyer struct pci_attach_args *pa = aux;
3917aa6248cScube struct ahci_pci_softc *psc = device_private(self);
3924c1d81b2Sjmcneill struct ahci_softc *sc = &psc->ah_sc;
39395ea24f1Sjakllsch bool ahci_cap_64bit;
39495ea24f1Sjakllsch bool ahci_bad_64bit;
395ceced892Stnn pcireg_t reg;
396920d7a6aSbouyer
397ee39397dScube sc->sc_atac.atac_dev = self;
3984137b5c8Scube
3998fa4dc6bSskrll int bar = ahci_pci_abar(pa);
4008fa4dc6bSskrll pcireg_t memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, bar);
4018fa4dc6bSskrll if (pci_mapreg_map(pa, bar, memtype, 0, &sc->sc_ahcit, &sc->sc_ahcih,
4028fa4dc6bSskrll NULL, &sc->sc_ahcis) != 0) {
4037aa6248cScube aprint_error_dev(self, "can't map ahci registers\n");
404920d7a6aSbouyer return;
405920d7a6aSbouyer }
4064c1d81b2Sjmcneill psc->sc_pc = pa->pa_pc;
4074c1d81b2Sjmcneill psc->sc_pcitag = pa->pa_tag;
4084c1d81b2Sjmcneill
409d8e1a7b6Sdrochner pci_aprint_devinfo(pa, "AHCI disk controller");
410920d7a6aSbouyer
41172c4d72dSjdolecek int counts[PCI_INTR_TYPE_SIZE] = {
41272c4d72dSjdolecek [PCI_INTR_TYPE_INTX] = 1,
41372c4d72dSjdolecek [PCI_INTR_TYPE_MSI] = 1,
41483226ad3Sjdolecek [PCI_INTR_TYPE_MSIX] = -1,
41572c4d72dSjdolecek };
41672c4d72dSjdolecek
4174374f2dbSskrll /* Allocate and establish the interrupt. */
41883226ad3Sjdolecek if (pci_intr_alloc(pa, &psc->sc_pihp, counts, PCI_INTR_TYPE_MSIX)) {
4194374f2dbSskrll aprint_error_dev(self, "can't allocate handler\n");
4204374f2dbSskrll goto fail;
421920d7a6aSbouyer }
4224374f2dbSskrll
42383226ad3Sjdolecek psc->sc_nintr = counts[pci_intr_type(pa->pa_pc, psc->sc_pihp[0])];
42483226ad3Sjdolecek psc->sc_ih = kmem_zalloc(sizeof(void *) * psc->sc_nintr, KM_SLEEP);
42583226ad3Sjdolecek sc->sc_intr_establish = ahci_pci_intr_establish;
42695ea24f1Sjakllsch
427920d7a6aSbouyer sc->sc_dmat = pa->pa_dmat;
4287794776bSxtraeme
4295a3c59bfSbouyer sc->sc_ahci_quirks = ahci_pci_has_quirk(PCI_VENDOR(pa->pa_id),
4308539c8f3Sbouyer PCI_PRODUCT(pa->pa_id));
4318539c8f3Sbouyer
43295ea24f1Sjakllsch ahci_cap_64bit = (AHCI_READ(sc, AHCI_CAP) & AHCI_CAP_64BIT) != 0;
4335a3c59bfSbouyer ahci_bad_64bit = ((sc->sc_ahci_quirks & AHCI_PCI_QUIRK_BAD64) != 0);
43495ea24f1Sjakllsch
43595ea24f1Sjakllsch if (pci_dma64_available(pa) && ahci_cap_64bit) {
43695ea24f1Sjakllsch if (!ahci_bad_64bit)
43795ea24f1Sjakllsch sc->sc_dmat = pa->pa_dmat64;
43895ea24f1Sjakllsch aprint_verbose_dev(self, "64-bit DMA%s\n",
43995ea24f1Sjakllsch (sc->sc_dmat == pa->pa_dmat) ? " unavailable" : "");
44095ea24f1Sjakllsch }
44195ea24f1Sjakllsch
4426b959e1dSmlelstv if (PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_RAID) {
44369b2d26eSmlelstv AHCIDEBUG_PRINT(("%s: RAID mode\n", AHCINAME(sc)), DEBUG_PROBE);
4447794776bSxtraeme sc->sc_atac_capflags = ATAC_CAP_RAID;
4456b959e1dSmlelstv } else {
44669b2d26eSmlelstv AHCIDEBUG_PRINT(("%s: SATA mode\n", AHCINAME(sc)), DEBUG_PROBE);
4476b959e1dSmlelstv }
4487794776bSxtraeme
449ceced892Stnn reg = pci_conf_read(psc->sc_pc, psc->sc_pcitag, PCI_COMMAND_STATUS_REG);
450ceced892Stnn reg |= (PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE);
451ceced892Stnn pci_conf_write(psc->sc_pc, psc->sc_pcitag, PCI_COMMAND_STATUS_REG, reg);
452ceced892Stnn
453920d7a6aSbouyer ahci_attach(sc);
4544c1d81b2Sjmcneill
4554c1d81b2Sjmcneill if (!pmf_device_register(self, NULL, ahci_pci_resume))
4564c1d81b2Sjmcneill aprint_error_dev(self, "couldn't establish power handler\n");
4574374f2dbSskrll
4584374f2dbSskrll return;
4594374f2dbSskrll fail:
4604374f2dbSskrll if (psc->sc_pihp != NULL) {
46183226ad3Sjdolecek pci_intr_release(psc->sc_pc, psc->sc_pihp, psc->sc_nintr);
4624374f2dbSskrll psc->sc_pihp = NULL;
4634374f2dbSskrll }
4644374f2dbSskrll if (sc->sc_ahcis) {
4654374f2dbSskrll bus_space_unmap(sc->sc_ahcit, sc->sc_ahcih, sc->sc_ahcis);
4664374f2dbSskrll sc->sc_ahcis = 0;
4674374f2dbSskrll }
4684374f2dbSskrll
4694374f2dbSskrll return;
4704374f2dbSskrll
4714c1d81b2Sjmcneill }
4724c1d81b2Sjmcneill
473654326faSjdolecek static void
ahci_pci_childdetached(device_t dv,device_t child)474654326faSjdolecek ahci_pci_childdetached(device_t dv, device_t child)
475654326faSjdolecek {
476654326faSjdolecek struct ahci_pci_softc *psc = device_private(dv);
477654326faSjdolecek struct ahci_softc *sc = &psc->ah_sc;
478654326faSjdolecek
479654326faSjdolecek ahci_childdetached(sc, child);
480654326faSjdolecek }
481654326faSjdolecek
4825630ecd4Sjakllsch static int
ahci_pci_detach(device_t dv,int flags)4835630ecd4Sjakllsch ahci_pci_detach(device_t dv, int flags)
4845630ecd4Sjakllsch {
4855630ecd4Sjakllsch struct ahci_pci_softc *psc;
4865630ecd4Sjakllsch struct ahci_softc *sc;
4875630ecd4Sjakllsch int rv;
4885630ecd4Sjakllsch
4895630ecd4Sjakllsch psc = device_private(dv);
4905630ecd4Sjakllsch sc = &psc->ah_sc;
4915630ecd4Sjakllsch
4925630ecd4Sjakllsch if ((rv = ahci_detach(sc, flags)))
4935630ecd4Sjakllsch return rv;
4945630ecd4Sjakllsch
4951ef7297cSdyoung pmf_device_deregister(dv);
4961ef7297cSdyoung
497830d6e2eSjdolecek if (psc->sc_ih != NULL) {
49883226ad3Sjdolecek for (int intr = 0; intr < psc->sc_nintr; intr++) {
49983226ad3Sjdolecek if (psc->sc_ih[intr] != NULL) {
50083226ad3Sjdolecek pci_intr_disestablish(psc->sc_pc,
50183226ad3Sjdolecek psc->sc_ih[intr]);
50283226ad3Sjdolecek psc->sc_ih[intr] = NULL;
50383226ad3Sjdolecek }
50483226ad3Sjdolecek }
50583226ad3Sjdolecek
50683226ad3Sjdolecek kmem_free(psc->sc_ih, sizeof(void *) * psc->sc_nintr);
507830d6e2eSjdolecek psc->sc_ih = NULL;
508830d6e2eSjdolecek }
5095630ecd4Sjakllsch
510596cd894Sjdolecek if (psc->sc_pihp != NULL) {
51183226ad3Sjdolecek pci_intr_release(psc->sc_pc, psc->sc_pihp, psc->sc_nintr);
512596cd894Sjdolecek psc->sc_pihp = NULL;
513596cd894Sjdolecek }
514596cd894Sjdolecek
5155630ecd4Sjakllsch bus_space_unmap(sc->sc_ahcit, sc->sc_ahcih, sc->sc_ahcis);
5165630ecd4Sjakllsch
5175630ecd4Sjakllsch return 0;
5185630ecd4Sjakllsch }
5195630ecd4Sjakllsch
5204c1d81b2Sjmcneill static bool
ahci_pci_resume(device_t dv,const pmf_qual_t * qual)521c1b390d4Sdyoung ahci_pci_resume(device_t dv, const pmf_qual_t *qual)
5224c1d81b2Sjmcneill {
5234c1d81b2Sjmcneill struct ahci_pci_softc *psc = device_private(dv);
5244c1d81b2Sjmcneill struct ahci_softc *sc = &psc->ah_sc;
5254c1d81b2Sjmcneill int s;
5264c1d81b2Sjmcneill
5274c1d81b2Sjmcneill s = splbio();
5285630ecd4Sjakllsch ahci_resume(sc);
5294c1d81b2Sjmcneill splx(s);
5304c1d81b2Sjmcneill
5314c1d81b2Sjmcneill return true;
532920d7a6aSbouyer }
533