10db7e66cSJonathan Chen /* 20db7e66cSJonathan Chen * Copyright (c) 2000,2001 Jonathan Chen. 30db7e66cSJonathan Chen * All rights reserved. 40db7e66cSJonathan Chen * 50db7e66cSJonathan Chen * Redistribution and use in source and binary forms, with or without 60db7e66cSJonathan Chen * modification, are permitted provided that the following conditions 70db7e66cSJonathan Chen * are met: 80db7e66cSJonathan Chen * 1. Redistributions of source code must retain the above copyright 90db7e66cSJonathan Chen * notice, this list of conditions, and the following disclaimer, 100db7e66cSJonathan Chen * without modification, immediately at the beginning of the file. 110db7e66cSJonathan Chen * 2. Redistributions in binary form must reproduce the above copyright 120db7e66cSJonathan Chen * notice, this list of conditions and the following disclaimer in 130db7e66cSJonathan Chen * the documentation and/or other materials provided with the 140db7e66cSJonathan Chen * distribution. 150db7e66cSJonathan Chen * 160db7e66cSJonathan Chen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 170db7e66cSJonathan Chen * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 180db7e66cSJonathan Chen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 190db7e66cSJonathan Chen * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 200db7e66cSJonathan Chen * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 210db7e66cSJonathan Chen * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 220db7e66cSJonathan Chen * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 230db7e66cSJonathan Chen * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 240db7e66cSJonathan Chen * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 250db7e66cSJonathan Chen * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 260db7e66cSJonathan Chen * SUCH DAMAGE. 270db7e66cSJonathan Chen * 280db7e66cSJonathan Chen * $FreeBSD$ 290db7e66cSJonathan Chen */ 300db7e66cSJonathan Chen 310db7e66cSJonathan Chen /* 320db7e66cSJonathan Chen * CIS Handling for the Cardbus Bus 330db7e66cSJonathan Chen */ 340db7e66cSJonathan Chen 350db7e66cSJonathan Chen #include <sys/param.h> 360db7e66cSJonathan Chen #include <sys/systm.h> 370db7e66cSJonathan Chen #include <sys/kernel.h> 380c95c705SJonathan Chen #include <sys/malloc.h> 390db7e66cSJonathan Chen 400db7e66cSJonathan Chen #include <sys/bus.h> 410db7e66cSJonathan Chen #include <machine/bus.h> 420db7e66cSJonathan Chen #include <machine/resource.h> 430db7e66cSJonathan Chen #include <sys/rman.h> 440db7e66cSJonathan Chen 457ba175acSWarner Losh #include <sys/pciio.h> 4663fa9f4cSJonathan Chen #include <dev/pci/pcivar.h> 4763fa9f4cSJonathan Chen #include <dev/pci/pcireg.h> 480db7e66cSJonathan Chen 490db7e66cSJonathan Chen #include <dev/cardbus/cardbusreg.h> 5063fa9f4cSJonathan Chen #include <dev/cardbus/cardbusvar.h> 510db7e66cSJonathan Chen #include <dev/cardbus/cardbus_cis.h> 520db7e66cSJonathan Chen 5380f10018STakanori Watanabe #include <dev/pccard/pccardvar.h> 540c95c705SJonathan Chen 55b3889b68SWarner Losh extern int cardbus_cis_debug; 56b3889b68SWarner Losh 57b3889b68SWarner Losh #define DPRINTF(a) if (cardbus_cis_debug) printf a 58b3889b68SWarner Losh #define DEVPRINTF(x) if (cardbus_cis_debug) device_printf x 59b3889b68SWarner Losh 600c95c705SJonathan Chen #define DECODE_PARAMS \ 61255b159fSJonathan Chen (device_t cbdev, device_t child, int id, int len, \ 6266e390feSWarner Losh uint8_t *tupledata, uint32_t start, uint32_t *off, \ 630c95c705SJonathan Chen struct tuple_callbacks *info) 640db7e66cSJonathan Chen 650c95c705SJonathan Chen struct tuple_callbacks { 660c95c705SJonathan Chen int id; 670db7e66cSJonathan Chen char *name; 680c95c705SJonathan Chen int (*func) DECODE_PARAMS; 690db7e66cSJonathan Chen }; 70255b159fSJonathan Chen 71255b159fSJonathan Chen #define DECODE_PROTOTYPE(NAME) static int decode_tuple_ ## NAME DECODE_PARAMS 72255b159fSJonathan Chen DECODE_PROTOTYPE(generic); 73255b159fSJonathan Chen DECODE_PROTOTYPE(nothing); 74255b159fSJonathan Chen DECODE_PROTOTYPE(copy); 75255b159fSJonathan Chen DECODE_PROTOTYPE(linktarget); 76255b159fSJonathan Chen DECODE_PROTOTYPE(vers_1); 77255b159fSJonathan Chen DECODE_PROTOTYPE(funcid); 78255b159fSJonathan Chen DECODE_PROTOTYPE(manfid); 79255b159fSJonathan Chen DECODE_PROTOTYPE(funce); 80255b159fSJonathan Chen DECODE_PROTOTYPE(bar); 81255b159fSJonathan Chen DECODE_PROTOTYPE(unhandled); 82255b159fSJonathan Chen DECODE_PROTOTYPE(end); 83255b159fSJonathan Chen static int cardbus_read_tuple_conf(device_t cbdev, device_t child, 8466e390feSWarner Losh uint32_t start, uint32_t *off, int *tupleid, int *len, 8566e390feSWarner Losh uint8_t *tupledata); 8663fa9f4cSJonathan Chen static int cardbus_read_tuple_mem(device_t cbdev, struct resource *res, 8766e390feSWarner Losh uint32_t start, uint32_t *off, int *tupleid, int *len, 8866e390feSWarner Losh uint8_t *tupledata); 89255b159fSJonathan Chen static int cardbus_read_tuple(device_t cbdev, device_t child, 9066e390feSWarner Losh struct resource *res, uint32_t start, uint32_t *off, 9166e390feSWarner Losh int *tupleid, int *len, uint8_t *tupledata); 9263fa9f4cSJonathan Chen static void cardbus_read_tuple_finish(device_t cbdev, device_t child, 9363fa9f4cSJonathan Chen int rid, struct resource *res); 9463fa9f4cSJonathan Chen static struct resource *cardbus_read_tuple_init(device_t cbdev, device_t child, 9566e390feSWarner Losh uint32_t *start, int *rid); 96255b159fSJonathan Chen static int decode_tuple(device_t cbdev, device_t child, int tupleid, 9766e390feSWarner Losh int len, uint8_t *tupledata, uint32_t start, 9866e390feSWarner Losh uint32_t *off, struct tuple_callbacks *callbacks); 99255b159fSJonathan Chen static int cardbus_parse_cis(device_t cbdev, device_t child, 100255b159fSJonathan Chen struct tuple_callbacks *callbacks); 10163fa9f4cSJonathan Chen static int barsort(const void *a, const void *b); 10263fa9f4cSJonathan Chen static int cardbus_alloc_resources(device_t cbdev, device_t child); 10363fa9f4cSJonathan Chen static void cardbus_add_map(device_t cbdev, device_t child, int reg); 10463fa9f4cSJonathan Chen static void cardbus_pickup_maps(device_t cbdev, device_t child); 10563fa9f4cSJonathan Chen 106255b159fSJonathan Chen 1070c95c705SJonathan Chen #define MAKETUPLE(NAME,FUNC) { CISTPL_ ## NAME, #NAME, decode_tuple_ ## FUNC } 1080db7e66cSJonathan Chen 1090db7e66cSJonathan Chen static char *funcnames[] = { 1100db7e66cSJonathan Chen "Multi-Functioned", 1110db7e66cSJonathan Chen "Memory", 1120db7e66cSJonathan Chen "Serial Port", 1130db7e66cSJonathan Chen "Parallel Port", 1140db7e66cSJonathan Chen "Fixed Disk", 1150db7e66cSJonathan Chen "Video Adaptor", 1160db7e66cSJonathan Chen "Network Adaptor", 1170db7e66cSJonathan Chen "AIMS", 1180db7e66cSJonathan Chen "SCSI", 1190db7e66cSJonathan Chen "Security" 1200db7e66cSJonathan Chen }; 1210db7e66cSJonathan Chen 12263fa9f4cSJonathan Chen struct cardbus_quirk { 12366e390feSWarner Losh uint32_t devid; /* Vendor/device of the card */ 12463fa9f4cSJonathan Chen int type; 12563fa9f4cSJonathan Chen #define CARDBUS_QUIRK_MAP_REG 1 /* PCI map register in weird place */ 12663fa9f4cSJonathan Chen int arg1; 12763fa9f4cSJonathan Chen int arg2; 12863fa9f4cSJonathan Chen }; 12963fa9f4cSJonathan Chen 13063fa9f4cSJonathan Chen struct cardbus_quirk cardbus_quirks[] = { 13163fa9f4cSJonathan Chen { 0 } 13263fa9f4cSJonathan Chen }; 13363fa9f4cSJonathan Chen 1340c95c705SJonathan Chen static struct cis_tupleinfo *cisread_buf; 1350c95c705SJonathan Chen static int ncisread_buf; 1360c95c705SJonathan Chen 137255b159fSJonathan Chen /* 138255b159fSJonathan Chen * Handler functions for various CIS tuples 139255b159fSJonathan Chen */ 140255b159fSJonathan Chen 1410db7e66cSJonathan Chen DECODE_PROTOTYPE(generic) 1420db7e66cSJonathan Chen { 1430db7e66cSJonathan Chen #ifdef CARDBUS_DEBUG 1440db7e66cSJonathan Chen int i; 1450db7e66cSJonathan Chen 1460db7e66cSJonathan Chen if (info) 1470db7e66cSJonathan Chen printf("TUPLE: %s [%d]:", info->name, len); 1480db7e66cSJonathan Chen else 1490db7e66cSJonathan Chen printf("TUPLE: Unknown(0x%02x) [%d]:", id, len); 1500db7e66cSJonathan Chen 1510db7e66cSJonathan Chen for (i = 0; i < len; i++) { 1520db7e66cSJonathan Chen if (i % 0x10 == 0 && len > 0x10) 1530db7e66cSJonathan Chen printf("\n 0x%02x:", i); 1547bec1dd5SJonathan Chen printf(" %02x", tupledata[i]); 1550db7e66cSJonathan Chen } 1560db7e66cSJonathan Chen printf("\n"); 1570db7e66cSJonathan Chen #endif 158a3133b58SWarner Losh return (0); 1590db7e66cSJonathan Chen } 1600db7e66cSJonathan Chen 1610c95c705SJonathan Chen DECODE_PROTOTYPE(nothing) 1620c95c705SJonathan Chen { 163a3133b58SWarner Losh return (0); 1640c95c705SJonathan Chen } 1650c95c705SJonathan Chen 1660c95c705SJonathan Chen DECODE_PROTOTYPE(copy) 1670c95c705SJonathan Chen { 1680c95c705SJonathan Chen struct cis_tupleinfo *tmpbuf; 1690c95c705SJonathan Chen 1700c95c705SJonathan Chen tmpbuf = malloc(sizeof(struct cis_tupleinfo) * (ncisread_buf+1), 17144956c98SAlfred Perlstein M_DEVBUF, 0); 1720c95c705SJonathan Chen if (ncisread_buf > 0) { 1730c95c705SJonathan Chen memcpy(tmpbuf, cisread_buf, 1740c95c705SJonathan Chen sizeof(struct cis_tupleinfo) * ncisread_buf); 1750c95c705SJonathan Chen free(cisread_buf, M_DEVBUF); 1760c95c705SJonathan Chen } 1770c95c705SJonathan Chen cisread_buf = tmpbuf; 1780c95c705SJonathan Chen 1790c95c705SJonathan Chen cisread_buf[ncisread_buf].id = id; 1800c95c705SJonathan Chen cisread_buf[ncisread_buf].len = len; 18144956c98SAlfred Perlstein cisread_buf[ncisread_buf].data = malloc(len, M_DEVBUF, 0); 1820c95c705SJonathan Chen memcpy(cisread_buf[ncisread_buf].data, tupledata, len); 1830c95c705SJonathan Chen ncisread_buf++; 184a3133b58SWarner Losh return (0); 1850c95c705SJonathan Chen } 1860c95c705SJonathan Chen 1870db7e66cSJonathan Chen DECODE_PROTOTYPE(linktarget) 1880db7e66cSJonathan Chen { 18949f158ccSJonathan Chen #ifdef CARDBUS_DEBUG 19049f158ccSJonathan Chen int i; 19149f158ccSJonathan Chen 19249f158ccSJonathan Chen printf("TUPLE: %s [%d]:", info->name, len); 19349f158ccSJonathan Chen 19449f158ccSJonathan Chen for (i = 0; i < len; i++) { 19549f158ccSJonathan Chen if (i % 0x10 == 0 && len > 0x10) 19649f158ccSJonathan Chen printf("\n 0x%02x:", i); 19749f158ccSJonathan Chen printf(" %02x", tupledata[i]); 19849f158ccSJonathan Chen } 19949f158ccSJonathan Chen printf("\n"); 20049f158ccSJonathan Chen #endif 2017bec1dd5SJonathan Chen if (len != 3 || tupledata[0] != 'C' || tupledata[1] != 'I' || 2027bec1dd5SJonathan Chen tupledata[2] != 'S') { 2030db7e66cSJonathan Chen printf("Invalid data for CIS Link Target!\n"); 204255b159fSJonathan Chen decode_tuple_generic(cbdev, child, id, len, tupledata, 20549f158ccSJonathan Chen start, off, info); 206a3133b58SWarner Losh return (EINVAL); 2070db7e66cSJonathan Chen } 208a3133b58SWarner Losh return (0); 2090db7e66cSJonathan Chen } 2100db7e66cSJonathan Chen 2110db7e66cSJonathan Chen DECODE_PROTOTYPE(vers_1) 2120db7e66cSJonathan Chen { 2130db7e66cSJonathan Chen int i; 214fbe9cff1SWarner Losh 2157bec1dd5SJonathan Chen printf("Product version: %d.%d\n", tupledata[0], tupledata[1]); 2160db7e66cSJonathan Chen printf("Product name: "); 2170db7e66cSJonathan Chen for (i = 2; i < len; i++) { 2187bec1dd5SJonathan Chen if (tupledata[i] == '\0') 2190db7e66cSJonathan Chen printf(" | "); 2207bec1dd5SJonathan Chen else if (tupledata[i] == 0xff) 2210db7e66cSJonathan Chen break; 2220db7e66cSJonathan Chen else 2237bec1dd5SJonathan Chen printf("%c", tupledata[i]); 2240db7e66cSJonathan Chen } 2250db7e66cSJonathan Chen printf("\n"); 226a3133b58SWarner Losh return (0); 2270db7e66cSJonathan Chen } 2280db7e66cSJonathan Chen 2290db7e66cSJonathan Chen DECODE_PROTOTYPE(funcid) 2300db7e66cSJonathan Chen { 231fbe9cff1SWarner Losh struct cardbus_devinfo *dinfo = device_get_ivars(child); 2320db7e66cSJonathan Chen int numnames = sizeof(funcnames) / sizeof(funcnames[0]); 233fbe9cff1SWarner Losh int i; 2340db7e66cSJonathan Chen 2350db7e66cSJonathan Chen printf("Functions: "); 2360db7e66cSJonathan Chen for (i = 0; i < len; i++) { 2377bec1dd5SJonathan Chen if (tupledata[i] < numnames) 2387bec1dd5SJonathan Chen printf("%s", funcnames[tupledata[i]]); 2390db7e66cSJonathan Chen else 2407bec1dd5SJonathan Chen printf("Unknown(%d)", tupledata[i]); 241255b159fSJonathan Chen if (i < len-1) 242255b159fSJonathan Chen printf(", "); 2430db7e66cSJonathan Chen } 244fbe9cff1SWarner Losh 245fbe9cff1SWarner Losh if (len > 0) 246fbe9cff1SWarner Losh dinfo->funcid = tupledata[0]; /* use first in list */ 2470db7e66cSJonathan Chen printf("\n"); 248a3133b58SWarner Losh return (0); 2490db7e66cSJonathan Chen } 2500db7e66cSJonathan Chen 2510db7e66cSJonathan Chen DECODE_PROTOTYPE(manfid) 2520db7e66cSJonathan Chen { 253fbe9cff1SWarner Losh struct cardbus_devinfo *dinfo = device_get_ivars(child); 2540db7e66cSJonathan Chen int i; 255fbe9cff1SWarner Losh 2560db7e66cSJonathan Chen printf("Manufacturer ID: "); 2570db7e66cSJonathan Chen for (i = 0; i < len; i++) 2587bec1dd5SJonathan Chen printf("%02x", tupledata[i]); 2590db7e66cSJonathan Chen printf("\n"); 260fbe9cff1SWarner Losh 261fbe9cff1SWarner Losh if (len == 5) { 262fbe9cff1SWarner Losh dinfo->mfrid = tupledata[1] | (tupledata[2]<<8); 263fbe9cff1SWarner Losh dinfo->prodid = tupledata[3] | (tupledata[4]<<8); 264fbe9cff1SWarner Losh } 265a3133b58SWarner Losh return (0); 2660db7e66cSJonathan Chen } 2670db7e66cSJonathan Chen 2680db7e66cSJonathan Chen DECODE_PROTOTYPE(funce) 2690db7e66cSJonathan Chen { 270fbe9cff1SWarner Losh struct cardbus_devinfo *dinfo = device_get_ivars(child); 271fbe9cff1SWarner Losh int type, i; 272fbe9cff1SWarner Losh 2730db7e66cSJonathan Chen printf("Function Extension: "); 2740db7e66cSJonathan Chen for (i = 0; i < len; i++) 2757bec1dd5SJonathan Chen printf("%02x", tupledata[i]); 2760db7e66cSJonathan Chen printf("\n"); 277fbe9cff1SWarner Losh if (len < 2) /* too short */ 278fbe9cff1SWarner Losh return (0); 279fbe9cff1SWarner Losh type = tupledata[0]; /* XXX <32 always? */ 280fbe9cff1SWarner Losh switch (dinfo->funcid) { 281fbe9cff1SWarner Losh case TPL_FUNC_SERIAL: 282fbe9cff1SWarner Losh if (type == TPL_FUNCE_SER_UART) { /* NB: len known > 1 */ 283fbe9cff1SWarner Losh dinfo->funce.sio.type = tupledata[1] & 0x1f; 284fbe9cff1SWarner Losh } 285fbe9cff1SWarner Losh dinfo->fepresent |= 1<<type; 286fbe9cff1SWarner Losh break; 287fbe9cff1SWarner Losh case TPL_FUNC_LAN: 288fbe9cff1SWarner Losh switch (type) { 289fbe9cff1SWarner Losh case TPL_FUNCE_LAN_TECH: 290fbe9cff1SWarner Losh dinfo->funce.lan.tech = tupledata[1]; /* XXX mask? */ 291fbe9cff1SWarner Losh break; 292fbe9cff1SWarner Losh #if 0 293fbe9cff1SWarner Losh case TPL_FUNCE_LAN_SPEED: 294fbe9cff1SWarner Losh for (i = 0; i < 3; i++) { 295fbe9cff1SWarner Losh if (dinfo->funce.lan.speed[i] == 0) { 296fbe9cff1SWarner Losh if (len > 4) { 297fbe9cff1SWarner Losh dinfo->funce.lan.speed[i] = 298fbe9cff1SWarner Losh ...; 299fbe9cff1SWarner Losh } 300fbe9cff1SWarner Losh break; 301fbe9cff1SWarner Losh } 302fbe9cff1SWarner Losh } 303fbe9cff1SWarner Losh break; 304fbe9cff1SWarner Losh #endif 305fbe9cff1SWarner Losh case TPL_FUNCE_LAN_MEDIA: 306fbe9cff1SWarner Losh for (i = 0; i < 4 && dinfo->funce.lan.media[i]; i++) { 307fbe9cff1SWarner Losh if (dinfo->funce.lan.media[i] == 0) { 308fbe9cff1SWarner Losh /* NB: len known > 1 */ 309fbe9cff1SWarner Losh dinfo->funce.lan.media[i] = 310fbe9cff1SWarner Losh tupledata[1]; /*XXX? mask */ 311fbe9cff1SWarner Losh break; 312fbe9cff1SWarner Losh } 313fbe9cff1SWarner Losh } 314fbe9cff1SWarner Losh break; 315fbe9cff1SWarner Losh case TPL_FUNCE_LAN_NID: 316fbe9cff1SWarner Losh if (len > 6) 317fbe9cff1SWarner Losh bcopy(&tupledata[1], dinfo->funce.lan.nid, 6); 318fbe9cff1SWarner Losh break; 319fbe9cff1SWarner Losh case TPL_FUNCE_LAN_CONN: 320fbe9cff1SWarner Losh dinfo->funce.lan.contype = tupledata[1];/*XXX mask? */ 321fbe9cff1SWarner Losh break; 322fbe9cff1SWarner Losh } 323fbe9cff1SWarner Losh dinfo->fepresent |= 1<<type; 324fbe9cff1SWarner Losh break; 325fbe9cff1SWarner Losh } 326a3133b58SWarner Losh return (0); 3270db7e66cSJonathan Chen } 3280db7e66cSJonathan Chen 3290db7e66cSJonathan Chen DECODE_PROTOTYPE(bar) 3300db7e66cSJonathan Chen { 33163fa9f4cSJonathan Chen struct cardbus_devinfo *dinfo = device_get_ivars(child); 3320db7e66cSJonathan Chen int type; 3330db7e66cSJonathan Chen int reg; 33466e390feSWarner Losh uint32_t bar; 3350db7e66cSJonathan Chen 336e6e272b9SScott Long if (len != 6) { 337e6e272b9SScott Long printf("*** ERROR *** BAR length not 6 (%d)\n", len); 338e6e272b9SScott Long return (EINVAL); 339e6e272b9SScott Long } 34066e390feSWarner Losh reg = *(uint16_t*)tupledata; 34166e390feSWarner Losh len = *(uint32_t*)(tupledata + 2); 3420db7e66cSJonathan Chen if (reg & TPL_BAR_REG_AS) { 3430db7e66cSJonathan Chen type = SYS_RES_IOPORT; 3440db7e66cSJonathan Chen } else { 3450db7e66cSJonathan Chen type = SYS_RES_MEMORY; 3460db7e66cSJonathan Chen } 3470db7e66cSJonathan Chen bar = (reg & TPL_BAR_REG_ASI_MASK) - 1; 348255b159fSJonathan Chen if (bar < 0 || bar > 5 || 349255b159fSJonathan Chen (type == SYS_RES_IOPORT && bar == 5)) { 350255b159fSJonathan Chen device_printf(cbdev, "Invalid BAR number: %02x(%02x)\n", 3510db7e66cSJonathan Chen reg, bar); 352a3133b58SWarner Losh return (0); 3530db7e66cSJonathan Chen } 3540db7e66cSJonathan Chen bar = CARDBUS_BASE0_REG + bar * 4; 35563fa9f4cSJonathan Chen if (type == SYS_RES_MEMORY) { 35663fa9f4cSJonathan Chen if (bar & TPL_BAR_REG_PREFETCHABLE) 35763fa9f4cSJonathan Chen dinfo->mprefetchable |= BARBIT(bar); 35863fa9f4cSJonathan Chen if (bar & TPL_BAR_REG_BELOW1MB) 35963fa9f4cSJonathan Chen dinfo->mbelow1mb |= BARBIT(bar); 36063fa9f4cSJonathan Chen } else if (type == SYS_RES_IOPORT) { 36163fa9f4cSJonathan Chen if (bar & TPL_BAR_REG_BELOW1MB) 36263fa9f4cSJonathan Chen dinfo->ibelow1mb |= BARBIT(bar); 3630db7e66cSJonathan Chen } 364e6e272b9SScott Long DEVPRINTF((cbdev, "Opening BAR: type=%s, bar=%02x, len=%04x%s%s\n", 36563fa9f4cSJonathan Chen (type == SYS_RES_MEMORY) ? "MEM" : "IO", bar, len, 36663fa9f4cSJonathan Chen (type == SYS_RES_MEMORY && dinfo->mprefetchable & BARBIT(bar)) ? 367e6e272b9SScott Long " (Prefetchable)" : "", type == SYS_RES_MEMORY ? 368e6e272b9SScott Long ((dinfo->mbelow1mb & BARBIT(bar)) ? " (Below 1Mb)" : "") : 369e6e272b9SScott Long (dinfo->ibelow1mb & BARBIT(bar)) ? " (Below 1Mb)" : "" )); 37063fa9f4cSJonathan Chen 3717ba175acSWarner Losh resource_list_add(&dinfo->pci.resources, type, bar, 0UL, ~0UL, len); 372e6e272b9SScott Long 3739fb92b64SScott Long /* 3749fb92b64SScott Long * Mark the appropriate bit in the PCI command register so that 37501f2fb65SWarner Losh * device drivers will know which type of BARs can be used. 3769fb92b64SScott Long */ 3779fb92b64SScott Long pci_enable_io(child, type); 378a3133b58SWarner Losh return (0); 3790db7e66cSJonathan Chen } 3800db7e66cSJonathan Chen 3810db7e66cSJonathan Chen DECODE_PROTOTYPE(unhandled) 3820db7e66cSJonathan Chen { 3830db7e66cSJonathan Chen printf("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len); 384a3133b58SWarner Losh return (-1); 3850db7e66cSJonathan Chen } 3860db7e66cSJonathan Chen 3870db7e66cSJonathan Chen DECODE_PROTOTYPE(end) 3880db7e66cSJonathan Chen { 3890c95c705SJonathan Chen printf("CIS reading done\n"); 390a3133b58SWarner Losh return (0); 3910db7e66cSJonathan Chen } 3920db7e66cSJonathan Chen 393255b159fSJonathan Chen /* 394255b159fSJonathan Chen * Functions to read the a tuple from the card 395255b159fSJonathan Chen */ 396255b159fSJonathan Chen 3970db7e66cSJonathan Chen static int 39866e390feSWarner Losh cardbus_read_tuple_conf(device_t cbdev, device_t child, uint32_t start, 39966e390feSWarner Losh uint32_t *off, int *tupleid, int *len, uint8_t *tupledata) 4007bec1dd5SJonathan Chen { 4017bec1dd5SJonathan Chen int i, j; 40266e390feSWarner Losh uint32_t e; 40366e390feSWarner Losh uint32_t loc; 4047bec1dd5SJonathan Chen 40563fa9f4cSJonathan Chen loc = start + *off; 40649f158ccSJonathan Chen 40749f158ccSJonathan Chen e = pci_read_config(child, loc - loc % 4, 4); 40849f158ccSJonathan Chen for (j = loc % 4; j > 0; j--) 4097bec1dd5SJonathan Chen e >>= 8; 4107bec1dd5SJonathan Chen *len = 0; 41149f158ccSJonathan Chen for (i = loc, j = -2; j < *len; j++, i++) { 4127bec1dd5SJonathan Chen if (i % 4 == 0) 4137bec1dd5SJonathan Chen e = pci_read_config(child, i, 4); 4147bec1dd5SJonathan Chen if (j == -2) 4157bec1dd5SJonathan Chen *tupleid = 0xff & e; 4167bec1dd5SJonathan Chen else if (j == -1) 4177bec1dd5SJonathan Chen *len = 0xff & e; 4187bec1dd5SJonathan Chen else 4197bec1dd5SJonathan Chen tupledata[j] = 0xff & e; 4207bec1dd5SJonathan Chen e >>= 8; 4217bec1dd5SJonathan Chen } 4227bec1dd5SJonathan Chen *off += *len + 2; 423a3133b58SWarner Losh return (0); 4247bec1dd5SJonathan Chen } 4257bec1dd5SJonathan Chen 4267bec1dd5SJonathan Chen static int 42766e390feSWarner Losh cardbus_read_tuple_mem(device_t cbdev, struct resource *res, uint32_t start, 42866e390feSWarner Losh uint32_t *off, int *tupleid, int *len, uint8_t *tupledata) 4290db7e66cSJonathan Chen { 43063fa9f4cSJonathan Chen bus_space_tag_t bt; 43163fa9f4cSJonathan Chen bus_space_handle_t bh; 43263fa9f4cSJonathan Chen int ret; 4330db7e66cSJonathan Chen 43463fa9f4cSJonathan Chen bt = rman_get_bustag(res); 43563fa9f4cSJonathan Chen bh = rman_get_bushandle(res); 4360db7e66cSJonathan Chen 43763fa9f4cSJonathan Chen *tupleid = bus_space_read_1(bt, bh, start + *off); 43863fa9f4cSJonathan Chen *len = bus_space_read_1(bt, bh, start + *off + 1); 43963fa9f4cSJonathan Chen bus_space_read_region_1(bt, bh, *off + start + 2, tupledata, *len); 44063fa9f4cSJonathan Chen ret = 0; 44163fa9f4cSJonathan Chen *off += *len + 2; 442a3133b58SWarner Losh return (ret); 4430db7e66cSJonathan Chen } 44463fa9f4cSJonathan Chen 44563fa9f4cSJonathan Chen static int 44663fa9f4cSJonathan Chen cardbus_read_tuple(device_t cbdev, device_t child, struct resource *res, 44766e390feSWarner Losh uint32_t start, uint32_t *off, int *tupleid, int *len, 44866e390feSWarner Losh uint8_t *tupledata) 44963fa9f4cSJonathan Chen { 45063fa9f4cSJonathan Chen if (res == (struct resource*)~0UL) { 451a3133b58SWarner Losh return (cardbus_read_tuple_conf(cbdev, child, start, off, 452a3133b58SWarner Losh tupleid, len, tupledata)); 45363fa9f4cSJonathan Chen } else { 454a3133b58SWarner Losh return (cardbus_read_tuple_mem(cbdev, res, start, off, 455a3133b58SWarner Losh tupleid, len, tupledata)); 45663fa9f4cSJonathan Chen } 45763fa9f4cSJonathan Chen } 45863fa9f4cSJonathan Chen 45963fa9f4cSJonathan Chen static void 46063fa9f4cSJonathan Chen cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid, 46163fa9f4cSJonathan Chen struct resource *res) 46263fa9f4cSJonathan Chen { 46363fa9f4cSJonathan Chen if (res != (struct resource*)~0UL) { 46463fa9f4cSJonathan Chen bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res); 46563fa9f4cSJonathan Chen pci_write_config(child, rid, 0, 4); 46663fa9f4cSJonathan Chen PCI_DISABLE_IO(cbdev, child, SYS_RES_MEMORY); 46763fa9f4cSJonathan Chen } 46863fa9f4cSJonathan Chen } 46963fa9f4cSJonathan Chen 47063fa9f4cSJonathan Chen static struct resource * 47166e390feSWarner Losh cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start, 47263fa9f4cSJonathan Chen int *rid) 47363fa9f4cSJonathan Chen { 47466e390feSWarner Losh uint32_t testval; 47566e390feSWarner Losh uint32_t size; 47663fa9f4cSJonathan Chen struct resource *res; 47763fa9f4cSJonathan Chen 47863fa9f4cSJonathan Chen switch (CARDBUS_CIS_SPACE(*start)) { 47963fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_TUPLE: 480e6e272b9SScott Long /* CIS in PCI config space need no initialization */ 48121677473SWarner Losh return ((struct resource*)~0UL); 48263fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR0: 48363fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR1: 48463fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR2: 48563fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR3: 48663fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR4: 48763fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR5: 48863fa9f4cSJonathan Chen *rid = CARDBUS_BASE0_REG + (CARDBUS_CIS_SPACE(*start) - 1) * 4; 48963fa9f4cSJonathan Chen break; 49063fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_ROM: 49163fa9f4cSJonathan Chen *rid = CARDBUS_ROM_REG; 492e6e272b9SScott Long #if 0 493e6e272b9SScott Long /* 494e6e272b9SScott Long * This mask doesn't contain the bit that actually enables 495e6e272b9SScott Long * the Option ROM. 496e6e272b9SScott Long */ 49763fa9f4cSJonathan Chen pci_write_config(child, *rid, CARDBUS_ROM_ADDRMASK, 4); 498e6e272b9SScott Long #endif 49963fa9f4cSJonathan Chen break; 50063fa9f4cSJonathan Chen default: 50163fa9f4cSJonathan Chen device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n", 50263fa9f4cSJonathan Chen CARDBUS_CIS_SPACE(*start)); 503a3133b58SWarner Losh return (NULL); 50463fa9f4cSJonathan Chen } 50563fa9f4cSJonathan Chen 50663fa9f4cSJonathan Chen /* figure out how much space we need */ 507e6e272b9SScott Long pci_write_config(child, *rid, 0xffffffff, 4); 50863fa9f4cSJonathan Chen testval = pci_read_config(child, *rid, 4); 509e6e272b9SScott Long 510e6e272b9SScott Long /* 511e6e272b9SScott Long * This bit has a different meaning depending if we are dealing 5121e06ae99SScott Long * with a normal BAR or an Option ROM BAR. 513e6e272b9SScott Long */ 514e6e272b9SScott Long if (((testval & 0x1) == 0x1) && (*rid != CARDBUS_ROM_REG)) { 51563fa9f4cSJonathan Chen device_printf(cbdev, "CIS Space is IO, expecting memory.\n"); 516a3133b58SWarner Losh return (NULL); 51763fa9f4cSJonathan Chen } 518e6e272b9SScott Long 51963fa9f4cSJonathan Chen size = CARDBUS_MAPREG_MEM_SIZE(testval); 520e6e272b9SScott Long /* XXX Is this some kind of hack? */ 52163fa9f4cSJonathan Chen if (size < 4096) 52263fa9f4cSJonathan Chen size = 4096; 52363fa9f4cSJonathan Chen /* allocate the memory space to read CIS */ 52463fa9f4cSJonathan Chen res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, rid, 0, ~0, size, 52563fa9f4cSJonathan Chen rman_make_alignment_flags(size) | RF_ACTIVE); 52663fa9f4cSJonathan Chen if (res == NULL) { 52763fa9f4cSJonathan Chen device_printf(cbdev, "Unable to allocate resource " 52863fa9f4cSJonathan Chen "to read CIS.\n"); 529a3133b58SWarner Losh return (NULL); 53063fa9f4cSJonathan Chen } 53163fa9f4cSJonathan Chen pci_write_config(child, *rid, 53263fa9f4cSJonathan Chen rman_get_start(res) | ((*rid == CARDBUS_ROM_REG)? 53363fa9f4cSJonathan Chen CARDBUS_ROM_ENABLE : 0), 53463fa9f4cSJonathan Chen 4); 53563fa9f4cSJonathan Chen PCI_ENABLE_IO(cbdev, child, SYS_RES_MEMORY); 53663fa9f4cSJonathan Chen 53763fa9f4cSJonathan Chen /* Flip to the right ROM image if CIS is in ROM */ 53863fa9f4cSJonathan Chen if (CARDBUS_CIS_SPACE(*start) == CARDBUS_CIS_ASI_ROM) { 53963fa9f4cSJonathan Chen bus_space_tag_t bt; 54063fa9f4cSJonathan Chen bus_space_handle_t bh; 54166e390feSWarner Losh uint32_t imagesize; 54266e390feSWarner Losh uint32_t imagebase = 0; 54366e390feSWarner Losh uint32_t pcidata; 54466e390feSWarner Losh uint16_t romsig; 54563fa9f4cSJonathan Chen int romnum = 0; 546e6e272b9SScott Long int imagenum; 54763fa9f4cSJonathan Chen 54863fa9f4cSJonathan Chen bt = rman_get_bustag(res); 54963fa9f4cSJonathan Chen bh = rman_get_bushandle(res); 55063fa9f4cSJonathan Chen 55163fa9f4cSJonathan Chen imagenum = CARDBUS_CIS_ASI_ROM_IMAGE(*start); 55263fa9f4cSJonathan Chen for (romnum = 0;; romnum++) { 553e6e272b9SScott Long romsig = bus_space_read_2(bt, bh, 554e6e272b9SScott Long imagebase + CARDBUS_EXROM_SIGNATURE); 555e6e272b9SScott Long if (romsig != 0xaa55) { 55663fa9f4cSJonathan Chen device_printf(cbdev, "Bad header in rom %d: " 557e6e272b9SScott Long "[%x] %04x\n", romnum, imagebase + 558e6e272b9SScott Long CARDBUS_EXROM_SIGNATURE, romsig); 55963fa9f4cSJonathan Chen bus_release_resource(cbdev, SYS_RES_MEMORY, 56063fa9f4cSJonathan Chen *rid, res); 56163fa9f4cSJonathan Chen *rid = 0; 562a3133b58SWarner Losh return (NULL); 56363fa9f4cSJonathan Chen } 564e6e272b9SScott Long 565e6e272b9SScott Long /* 566e6e272b9SScott Long * If this was the Option ROM image that we were 567e6e272b9SScott Long * looking for, then we are done. 568e6e272b9SScott Long */ 569e6e272b9SScott Long if (romnum == imagenum) 570e6e272b9SScott Long break; 571e6e272b9SScott Long 572e6e272b9SScott Long /* Find out where the next Option ROM image is */ 573e6e272b9SScott Long pcidata = imagebase + bus_space_read_2(bt, bh, 574e6e272b9SScott Long imagebase + CARDBUS_EXROM_DATA_PTR); 57563fa9f4cSJonathan Chen imagesize = bus_space_read_2(bt, bh, 576e6e272b9SScott Long pcidata + CARDBUS_EXROM_DATA_IMAGE_LENGTH); 5770db7e66cSJonathan Chen 5787bec1dd5SJonathan Chen if (imagesize == 0) { 5790db7e66cSJonathan Chen /* 5800db7e66cSJonathan Chen * XXX some ROMs seem to have this as zero, 5810db7e66cSJonathan Chen * can we assume this means 1 block? 5820db7e66cSJonathan Chen */ 583e6e272b9SScott Long device_printf(cbdev, "Warning, size of Option " 584e6e272b9SScott Long "ROM image %d is 0 bytes, assuming 512 " 585e6e272b9SScott Long "bytes.\n", romnum); 5860db7e66cSJonathan Chen imagesize = 1; 5877bec1dd5SJonathan Chen } 588e6e272b9SScott Long 589e6e272b9SScott Long /* Image size is in 512 byte units */ 5900db7e66cSJonathan Chen imagesize <<= 9; 5910db7e66cSJonathan Chen 592e6e272b9SScott Long if ((bus_space_read_1(bt, bh, pcidata + 5931e06ae99SScott Long CARDBUS_EXROM_DATA_INDICATOR) & 0x80) != 0) { 594e6e272b9SScott Long device_printf(cbdev, "Cannot find CIS in " 595e6e272b9SScott Long "Option ROM\n"); 596e6e272b9SScott Long bus_release_resource(cbdev, SYS_RES_MEMORY, 597e6e272b9SScott Long *rid, res); 598e6e272b9SScott Long *rid = 0; 599a3133b58SWarner Losh return (NULL); 6000db7e66cSJonathan Chen } 601e6e272b9SScott Long imagebase += imagesize; 6020db7e66cSJonathan Chen } 603e6e272b9SScott Long *start = imagebase + CARDBUS_CIS_ADDR(*start); 6040db7e66cSJonathan Chen } else { 605e6e272b9SScott Long *start = CARDBUS_CIS_ADDR(*start); 6060db7e66cSJonathan Chen } 607e6e272b9SScott Long 608a3133b58SWarner Losh return (res); 6097bec1dd5SJonathan Chen } 6107bec1dd5SJonathan Chen 611255b159fSJonathan Chen /* 612255b159fSJonathan Chen * Dispatch the right handler function per tuple 613255b159fSJonathan Chen */ 614255b159fSJonathan Chen 6157bec1dd5SJonathan Chen static int 616255b159fSJonathan Chen decode_tuple(device_t cbdev, device_t child, int tupleid, int len, 61766e390feSWarner Losh uint8_t *tupledata, uint32_t start, uint32_t *off, 6180c95c705SJonathan Chen struct tuple_callbacks *callbacks) 6197bec1dd5SJonathan Chen { 6207bec1dd5SJonathan Chen int i; 6210c95c705SJonathan Chen for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) { 6220c95c705SJonathan Chen if (tupleid == callbacks[i].id) 623a3133b58SWarner Losh return (callbacks[i].func(cbdev, child, tupleid, len, 624a3133b58SWarner Losh tupledata, start, off, &callbacks[i])); 6257bec1dd5SJonathan Chen } 6267bec1dd5SJonathan Chen 62749f158ccSJonathan Chen if (tupleid < CISTPL_CUSTOMSTART) { 628255b159fSJonathan Chen device_printf(cbdev, "Undefined tuple encountered, " 629255b159fSJonathan Chen "CIS parsing terminated\n"); 630a3133b58SWarner Losh return (EINVAL); 63149f158ccSJonathan Chen } 632a3133b58SWarner Losh return (callbacks[i].func(cbdev, child, tupleid, len, 633a3133b58SWarner Losh tupledata, start, off, NULL)); 6340db7e66cSJonathan Chen } 6350db7e66cSJonathan Chen 6360c95c705SJonathan Chen static int 637255b159fSJonathan Chen cardbus_parse_cis(device_t cbdev, device_t child, 6380c95c705SJonathan Chen struct tuple_callbacks *callbacks) 6390db7e66cSJonathan Chen { 64066e390feSWarner Losh uint8_t tupledata[MAXTUPLESIZE]; 6417bec1dd5SJonathan Chen int tupleid; 6427bec1dd5SJonathan Chen int len; 6437bec1dd5SJonathan Chen int expect_linktarget; 64466e390feSWarner Losh uint32_t start, off; 64563fa9f4cSJonathan Chen struct resource *res; 64663fa9f4cSJonathan Chen int rid; 6470db7e66cSJonathan Chen 6480db7e66cSJonathan Chen bzero(tupledata, MAXTUPLESIZE); 6497bec1dd5SJonathan Chen expect_linktarget = TRUE; 650e6e272b9SScott Long if ((start = pci_read_config(child, CARDBUS_CIS_REG, 4)) == 0) 651e6e272b9SScott Long return (ENXIO); 65249f158ccSJonathan Chen off = 0; 65363fa9f4cSJonathan Chen res = cardbus_read_tuple_init(cbdev, child, &start, &rid); 65463fa9f4cSJonathan Chen if (res == NULL) 655a3133b58SWarner Losh return (ENXIO); 6567bec1dd5SJonathan Chen do { 65763fa9f4cSJonathan Chen if (0 != cardbus_read_tuple(cbdev, child, res, start, &off, 65863fa9f4cSJonathan Chen &tupleid, &len, tupledata)) { 65963fa9f4cSJonathan Chen device_printf(cbdev, "Failed to read CIS.\n"); 66063fa9f4cSJonathan Chen cardbus_read_tuple_finish(cbdev, child, rid, res); 661a3133b58SWarner Losh return (ENXIO); 66263fa9f4cSJonathan Chen } 6637bec1dd5SJonathan Chen 6647bec1dd5SJonathan Chen if (expect_linktarget && tupleid != CISTPL_LINKTARGET) { 665255b159fSJonathan Chen device_printf(cbdev, "Expecting link target, got 0x%x\n", 6667bec1dd5SJonathan Chen tupleid); 66763fa9f4cSJonathan Chen cardbus_read_tuple_finish(cbdev, child, rid, res); 668a3133b58SWarner Losh return (EINVAL); 6697bec1dd5SJonathan Chen } 670255b159fSJonathan Chen expect_linktarget = decode_tuple(cbdev, child, tupleid, len, 67163fa9f4cSJonathan Chen tupledata, start, &off, callbacks); 67263fa9f4cSJonathan Chen if (expect_linktarget != 0) { 67363fa9f4cSJonathan Chen cardbus_read_tuple_finish(cbdev, child, rid, res); 674a3133b58SWarner Losh return (expect_linktarget); 67563fa9f4cSJonathan Chen } 6767bec1dd5SJonathan Chen } while (tupleid != CISTPL_END); 67763fa9f4cSJonathan Chen cardbus_read_tuple_finish(cbdev, child, rid, res); 678a3133b58SWarner Losh return (0); 6790db7e66cSJonathan Chen } 6800db7e66cSJonathan Chen 68163fa9f4cSJonathan Chen static int 68263fa9f4cSJonathan Chen barsort(const void *a, const void *b) 68363fa9f4cSJonathan Chen { 68478b226dcSAlfred Perlstein return ((*(const struct resource_list_entry * const *)b)->count - 68578b226dcSAlfred Perlstein (*(const struct resource_list_entry * const *)a)->count); 68663fa9f4cSJonathan Chen } 68763fa9f4cSJonathan Chen 68863fa9f4cSJonathan Chen static int 68963fa9f4cSJonathan Chen cardbus_alloc_resources(device_t cbdev, device_t child) 69063fa9f4cSJonathan Chen { 69163fa9f4cSJonathan Chen struct cardbus_devinfo *dinfo = device_get_ivars(child); 69263fa9f4cSJonathan Chen int count; 69363fa9f4cSJonathan Chen struct resource_list_entry *rle; 69463fa9f4cSJonathan Chen struct resource_list_entry **barlist; 69563fa9f4cSJonathan Chen int tmp; 69666e390feSWarner Losh uint32_t mem_psize = 0, mem_nsize = 0, io_size = 0; 69763fa9f4cSJonathan Chen struct resource *res; 69866e390feSWarner Losh uint32_t start,end; 69921677473SWarner Losh int rid, flags; 70063fa9f4cSJonathan Chen 70163fa9f4cSJonathan Chen count = 0; 70221677473SWarner Losh SLIST_FOREACH(rle, &dinfo->pci.resources, link) { 70363fa9f4cSJonathan Chen count++; 70421677473SWarner Losh } 70563fa9f4cSJonathan Chen if (count == 0) 706a3133b58SWarner Losh return (0); 70763fa9f4cSJonathan Chen barlist = malloc(sizeof(struct resource_list_entry*) * count, M_DEVBUF, 70844956c98SAlfred Perlstein 0); 70963fa9f4cSJonathan Chen count = 0; 71021677473SWarner Losh SLIST_FOREACH(rle, &dinfo->pci.resources, link) { 71163fa9f4cSJonathan Chen barlist[count] = rle; 71263fa9f4cSJonathan Chen if (rle->type == SYS_RES_IOPORT) { 71363fa9f4cSJonathan Chen io_size += rle->count; 71463fa9f4cSJonathan Chen } else if (rle->type == SYS_RES_MEMORY) { 71563fa9f4cSJonathan Chen if (dinfo->mprefetchable & BARBIT(rle->rid)) 71663fa9f4cSJonathan Chen mem_psize += rle->count; 71763fa9f4cSJonathan Chen else 71863fa9f4cSJonathan Chen mem_nsize += rle->count; 71963fa9f4cSJonathan Chen } 72063fa9f4cSJonathan Chen count++; 72163fa9f4cSJonathan Chen } 72263fa9f4cSJonathan Chen 72363fa9f4cSJonathan Chen /* 72463fa9f4cSJonathan Chen * We want to allocate the largest resource first, so that our 72563fa9f4cSJonathan Chen * allocated memory is packed. 72663fa9f4cSJonathan Chen */ 72763fa9f4cSJonathan Chen qsort(barlist, count, sizeof(struct resource_list_entry*), barsort); 72863fa9f4cSJonathan Chen 72963fa9f4cSJonathan Chen /* Allocate prefetchable memory */ 73063fa9f4cSJonathan Chen flags = 0; 73163fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 73263fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL && 73363fa9f4cSJonathan Chen barlist[tmp]->type == SYS_RES_MEMORY && 73463fa9f4cSJonathan Chen dinfo->mprefetchable & BARBIT(barlist[tmp]->rid)) { 73563fa9f4cSJonathan Chen flags = rman_make_alignment_flags(barlist[tmp]->count); 73663fa9f4cSJonathan Chen break; 73763fa9f4cSJonathan Chen } 73863fa9f4cSJonathan Chen } 73963fa9f4cSJonathan Chen if (flags > 0) { /* If any prefetchable memory is requested... */ 74063fa9f4cSJonathan Chen /* 74163fa9f4cSJonathan Chen * First we allocate one big space for all resources of this 74263fa9f4cSJonathan Chen * type. We do this because our parent, pccbb, needs to open 74363fa9f4cSJonathan Chen * a window to forward all addresses within the window, and 74463fa9f4cSJonathan Chen * it would be best if nobody else has resources allocated 74563fa9f4cSJonathan Chen * within the window. 74663fa9f4cSJonathan Chen * (XXX: Perhaps there might be a better way to do this?) 74763fa9f4cSJonathan Chen */ 74863fa9f4cSJonathan Chen rid = 0; 74963fa9f4cSJonathan Chen res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0, 75063fa9f4cSJonathan Chen (dinfo->mprefetchable & dinfo->mbelow1mb)?0xFFFFF:~0UL, 75163fa9f4cSJonathan Chen mem_psize, flags); 75263fa9f4cSJonathan Chen start = rman_get_start(res); 75363fa9f4cSJonathan Chen end = rman_get_end(res); 75463fa9f4cSJonathan Chen DEVPRINTF((cbdev, "Prefetchable memory at %x-%x\n", start, end)); 75563fa9f4cSJonathan Chen /* 75663fa9f4cSJonathan Chen * Now that we know the region is free, release it and hand it 75763fa9f4cSJonathan Chen * out piece by piece. 75863fa9f4cSJonathan Chen */ 75963fa9f4cSJonathan Chen bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res); 76063fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 76163fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL && 76263fa9f4cSJonathan Chen barlist[tmp]->type == SYS_RES_MEMORY && 76363fa9f4cSJonathan Chen dinfo->mprefetchable & BARBIT(barlist[tmp]->rid)) { 76463fa9f4cSJonathan Chen barlist[tmp]->res = bus_alloc_resource(cbdev, 76563fa9f4cSJonathan Chen barlist[tmp]->type, 76663fa9f4cSJonathan Chen &barlist[tmp]->rid, start, end, 76763fa9f4cSJonathan Chen barlist[tmp]->count, 76863fa9f4cSJonathan Chen rman_make_alignment_flags( 76963fa9f4cSJonathan Chen barlist[tmp]->count)); 77063fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL) { 77163fa9f4cSJonathan Chen mem_nsize += barlist[tmp]->count; 77263fa9f4cSJonathan Chen dinfo->mprefetchable &= 77363fa9f4cSJonathan Chen ~BARBIT(barlist[tmp]->rid); 77463fa9f4cSJonathan Chen DEVPRINTF((cbdev, "Cannot pre-allocate " 77563fa9f4cSJonathan Chen "prefetchable memory, will try as " 77663fa9f4cSJonathan Chen "non-prefetchable.\n")); 77721677473SWarner Losh } else { 77863fa9f4cSJonathan Chen barlist[tmp]->start = 77963fa9f4cSJonathan Chen rman_get_start(barlist[tmp]->res); 78063fa9f4cSJonathan Chen barlist[tmp]->end = 78163fa9f4cSJonathan Chen rman_get_end(barlist[tmp]->res); 78263fa9f4cSJonathan Chen pci_write_config(child, 78363fa9f4cSJonathan Chen barlist[tmp]->rid, 78463fa9f4cSJonathan Chen barlist[tmp]->start, 4); 78563fa9f4cSJonathan Chen DEVPRINTF((cbdev, "Prefetchable memory " 78663fa9f4cSJonathan Chen "rid=%x at %lx-%lx\n", 78763fa9f4cSJonathan Chen barlist[tmp]->rid, 78863fa9f4cSJonathan Chen barlist[tmp]->start, 78963fa9f4cSJonathan Chen barlist[tmp]->end)); 79063fa9f4cSJonathan Chen } 79163fa9f4cSJonathan Chen } 79263fa9f4cSJonathan Chen } 79321677473SWarner Losh } 79463fa9f4cSJonathan Chen 79563fa9f4cSJonathan Chen /* Allocate non-prefetchable memory */ 79663fa9f4cSJonathan Chen flags = 0; 79763fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 79863fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL && 79963fa9f4cSJonathan Chen barlist[tmp]->type == SYS_RES_MEMORY) { 80063fa9f4cSJonathan Chen flags = rman_make_alignment_flags(barlist[tmp]->count); 80163fa9f4cSJonathan Chen break; 80263fa9f4cSJonathan Chen } 80363fa9f4cSJonathan Chen } 80463fa9f4cSJonathan Chen if (flags > 0) { /* If any non-prefetchable memory is requested... */ 80563fa9f4cSJonathan Chen /* 80663fa9f4cSJonathan Chen * First we allocate one big space for all resources of this 80763fa9f4cSJonathan Chen * type. We do this because our parent, pccbb, needs to open 80863fa9f4cSJonathan Chen * a window to forward all addresses within the window, and 80963fa9f4cSJonathan Chen * it would be best if nobody else has resources allocated 81063fa9f4cSJonathan Chen * within the window. 81163fa9f4cSJonathan Chen * (XXX: Perhaps there might be a better way to do this?) 81263fa9f4cSJonathan Chen */ 81363fa9f4cSJonathan Chen rid = 0; 81463fa9f4cSJonathan Chen res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0, 81563fa9f4cSJonathan Chen ((~dinfo->mprefetchable) & dinfo->mbelow1mb)?0xFFFFF:~0UL, 81663fa9f4cSJonathan Chen mem_nsize, flags); 81763fa9f4cSJonathan Chen start = rman_get_start(res); 81863fa9f4cSJonathan Chen end = rman_get_end(res); 81963fa9f4cSJonathan Chen DEVPRINTF((cbdev, "Non-prefetchable memory at %x-%x\n", 82063fa9f4cSJonathan Chen start, end)); 82163fa9f4cSJonathan Chen /* 82263fa9f4cSJonathan Chen * Now that we know the region is free, release it and hand it 82363fa9f4cSJonathan Chen * out piece by piece. 82463fa9f4cSJonathan Chen */ 82563fa9f4cSJonathan Chen bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res); 82663fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 82763fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL && 82863fa9f4cSJonathan Chen barlist[tmp]->type == SYS_RES_MEMORY) { 82963fa9f4cSJonathan Chen barlist[tmp]->res = bus_alloc_resource(cbdev, 83063fa9f4cSJonathan Chen barlist[tmp]->type, &barlist[tmp]->rid, 83163fa9f4cSJonathan Chen start, end, barlist[tmp]->count, 83263fa9f4cSJonathan Chen rman_make_alignment_flags( 83363fa9f4cSJonathan Chen barlist[tmp]->count)); 83463fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL) { 83563fa9f4cSJonathan Chen DEVPRINTF((cbdev, "Cannot pre-allocate " 83663fa9f4cSJonathan Chen "memory for cardbus device\n")); 837214c0b3dSWarner Losh free(barlist, M_DEVBUF); 8387ba175acSWarner Losh return (ENOMEM); 83963fa9f4cSJonathan Chen } 84063fa9f4cSJonathan Chen barlist[tmp]->start = 84163fa9f4cSJonathan Chen rman_get_start(barlist[tmp]->res); 84263fa9f4cSJonathan Chen barlist[tmp]->end = rman_get_end( 84363fa9f4cSJonathan Chen barlist[tmp]->res); 84463fa9f4cSJonathan Chen pci_write_config(child, barlist[tmp]->rid, 84563fa9f4cSJonathan Chen barlist[tmp]->start, 4); 84663fa9f4cSJonathan Chen DEVPRINTF((cbdev, "Non-prefetchable memory " 84763fa9f4cSJonathan Chen "rid=%x at %lx-%lx (%lx)\n", 84863fa9f4cSJonathan Chen barlist[tmp]->rid, barlist[tmp]->start, 84963fa9f4cSJonathan Chen barlist[tmp]->end, barlist[tmp]->count)); 85063fa9f4cSJonathan Chen } 85163fa9f4cSJonathan Chen } 85263fa9f4cSJonathan Chen } 85363fa9f4cSJonathan Chen 85463fa9f4cSJonathan Chen /* Allocate IO ports */ 85563fa9f4cSJonathan Chen flags = 0; 85663fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 85763fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL && 85863fa9f4cSJonathan Chen barlist[tmp]->type == SYS_RES_IOPORT) { 85963fa9f4cSJonathan Chen flags = rman_make_alignment_flags(barlist[tmp]->count); 86063fa9f4cSJonathan Chen break; 86163fa9f4cSJonathan Chen } 86263fa9f4cSJonathan Chen } 86363fa9f4cSJonathan Chen if (flags > 0) { /* If any IO port is requested... */ 86463fa9f4cSJonathan Chen /* 86563fa9f4cSJonathan Chen * First we allocate one big space for all resources of this 86663fa9f4cSJonathan Chen * type. We do this because our parent, pccbb, needs to open 86763fa9f4cSJonathan Chen * a window to forward all addresses within the window, and 86863fa9f4cSJonathan Chen * it would be best if nobody else has resources allocated 86963fa9f4cSJonathan Chen * within the window. 87063fa9f4cSJonathan Chen * (XXX: Perhaps there might be a better way to do this?) 87163fa9f4cSJonathan Chen */ 87263fa9f4cSJonathan Chen rid = 0; 87321677473SWarner Losh res = bus_alloc_resource(cbdev, SYS_RES_IOPORT, &rid, 0, 87421677473SWarner Losh (dinfo->ibelow1mb)?0xFFFFF:~0UL, io_size, flags); 87563fa9f4cSJonathan Chen start = rman_get_start(res); 87663fa9f4cSJonathan Chen end = rman_get_end(res); 87763fa9f4cSJonathan Chen DEVPRINTF((cbdev, "IO port at %x-%x\n", start, end)); 87863fa9f4cSJonathan Chen /* 87963fa9f4cSJonathan Chen * Now that we know the region is free, release it and hand it 88021677473SWarner Losh * out piece by piece. 88163fa9f4cSJonathan Chen */ 88263fa9f4cSJonathan Chen bus_release_resource(cbdev, SYS_RES_IOPORT, rid, res); 88363fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 88463fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL && 88563fa9f4cSJonathan Chen barlist[tmp]->type == SYS_RES_IOPORT) { 88663fa9f4cSJonathan Chen barlist[tmp]->res = bus_alloc_resource(cbdev, 88763fa9f4cSJonathan Chen barlist[tmp]->type, &barlist[tmp]->rid, 88863fa9f4cSJonathan Chen start, end, barlist[tmp]->count, 88963fa9f4cSJonathan Chen rman_make_alignment_flags( 89063fa9f4cSJonathan Chen barlist[tmp]->count)); 89163fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL) { 89263fa9f4cSJonathan Chen DEVPRINTF((cbdev, "Cannot pre-allocate " 89363fa9f4cSJonathan Chen "IO port for cardbus device\n")); 894214c0b3dSWarner Losh free(barlist, M_DEVBUF); 895a3133b58SWarner Losh return (ENOMEM); 89663fa9f4cSJonathan Chen } 89763fa9f4cSJonathan Chen barlist[tmp]->start = 89863fa9f4cSJonathan Chen rman_get_start(barlist[tmp]->res); 89963fa9f4cSJonathan Chen barlist[tmp]->end = 90063fa9f4cSJonathan Chen rman_get_end(barlist[tmp]->res); 90163fa9f4cSJonathan Chen pci_write_config(child, barlist[tmp]->rid, 90263fa9f4cSJonathan Chen barlist[tmp]->start, 4); 90363fa9f4cSJonathan Chen DEVPRINTF((cbdev, "IO port rid=%x at %lx-%lx\n", 90463fa9f4cSJonathan Chen barlist[tmp]->rid, barlist[tmp]->start, 90563fa9f4cSJonathan Chen barlist[tmp]->end)); 90663fa9f4cSJonathan Chen } 90763fa9f4cSJonathan Chen } 90863fa9f4cSJonathan Chen } 90963fa9f4cSJonathan Chen 91063fa9f4cSJonathan Chen /* Allocate IRQ */ 91163fa9f4cSJonathan Chen rid = 0; 91263fa9f4cSJonathan Chen res = bus_alloc_resource(cbdev, SYS_RES_IRQ, &rid, 0, ~0UL, 1, 91363fa9f4cSJonathan Chen RF_SHAREABLE); 91421677473SWarner Losh resource_list_add(&dinfo->pci.resources, SYS_RES_IRQ, rid, 91521677473SWarner Losh rman_get_start(res), rman_get_end(res), 1); 91621677473SWarner Losh rle = resource_list_find(&dinfo->pci.resources, SYS_RES_IRQ, rid); 91721677473SWarner Losh rle->res = res; 91821677473SWarner Losh dinfo->pci.cfg.intline = rman_get_start(res); 91921677473SWarner Losh pci_write_config(child, PCIR_INTLINE, rman_get_start(res), 1); 92063fa9f4cSJonathan Chen 921214c0b3dSWarner Losh free(barlist, M_DEVBUF); 922a3133b58SWarner Losh return (0); 92363fa9f4cSJonathan Chen } 92463fa9f4cSJonathan Chen 92563fa9f4cSJonathan Chen /* 92663fa9f4cSJonathan Chen * Adding a memory/io resource (sans CIS) 92763fa9f4cSJonathan Chen */ 92863fa9f4cSJonathan Chen 92963fa9f4cSJonathan Chen static void 93063fa9f4cSJonathan Chen cardbus_add_map(device_t cbdev, device_t child, int reg) 93163fa9f4cSJonathan Chen { 93263fa9f4cSJonathan Chen struct cardbus_devinfo *dinfo = device_get_ivars(child); 93321677473SWarner Losh struct resource_list_entry *rle; 93466e390feSWarner Losh uint32_t size; 93566e390feSWarner Losh uint32_t testval; 93663fa9f4cSJonathan Chen int type; 93763fa9f4cSJonathan Chen 93821677473SWarner Losh SLIST_FOREACH(rle, &dinfo->pci.resources, link) { 93921677473SWarner Losh if (rle->rid == reg) 94063fa9f4cSJonathan Chen return; 94121677473SWarner Losh } 94263fa9f4cSJonathan Chen 94363fa9f4cSJonathan Chen if (reg == CARDBUS_ROM_REG) 94463fa9f4cSJonathan Chen testval = CARDBUS_ROM_ADDRMASK; 94563fa9f4cSJonathan Chen else 94663fa9f4cSJonathan Chen testval = ~0; 94763fa9f4cSJonathan Chen 94863fa9f4cSJonathan Chen pci_write_config(child, reg, testval, 4); 94963fa9f4cSJonathan Chen testval = pci_read_config(child, reg, 4); 95063fa9f4cSJonathan Chen 95163fa9f4cSJonathan Chen if (testval == ~0 || testval == 0) 95263fa9f4cSJonathan Chen return; 95363fa9f4cSJonathan Chen 95463fa9f4cSJonathan Chen if ((testval & 1) == 0) 95563fa9f4cSJonathan Chen type = SYS_RES_MEMORY; 95663fa9f4cSJonathan Chen else 95763fa9f4cSJonathan Chen type = SYS_RES_IOPORT; 95863fa9f4cSJonathan Chen 95963fa9f4cSJonathan Chen size = CARDBUS_MAPREG_MEM_SIZE(testval); 96021677473SWarner Losh device_printf(cbdev, "Resource not specified in CIS: id=%x, size=%x\n", 96121677473SWarner Losh reg, size); 96221677473SWarner Losh resource_list_add(&dinfo->pci.resources, type, reg, 0UL, ~0UL, size); 96363fa9f4cSJonathan Chen } 96463fa9f4cSJonathan Chen 96563fa9f4cSJonathan Chen static void 96663fa9f4cSJonathan Chen cardbus_pickup_maps(device_t cbdev, device_t child) 96763fa9f4cSJonathan Chen { 96863fa9f4cSJonathan Chen struct cardbus_devinfo *dinfo = device_get_ivars(child); 96963fa9f4cSJonathan Chen struct cardbus_quirk *q; 97063fa9f4cSJonathan Chen int reg; 97163fa9f4cSJonathan Chen 97263fa9f4cSJonathan Chen /* 97363fa9f4cSJonathan Chen * Try to pick up any resources that was not specified in CIS. 97463fa9f4cSJonathan Chen * Some devices (eg, 3c656) does not list all resources required by 97563fa9f4cSJonathan Chen * the driver in its CIS. 97663fa9f4cSJonathan Chen * XXX: should we do this or use quirks? 97763fa9f4cSJonathan Chen */ 9787ba175acSWarner Losh for (reg = 0; reg < dinfo->pci.cfg.nummaps; reg++) { 97963fa9f4cSJonathan Chen cardbus_add_map(cbdev, child, PCIR_MAPS + reg * 4); 98063fa9f4cSJonathan Chen } 98163fa9f4cSJonathan Chen 98263fa9f4cSJonathan Chen for (q = &cardbus_quirks[0]; q->devid; q++) { 98321677473SWarner Losh if (q->devid == ((dinfo->pci.cfg.device << 16) | dinfo->pci.cfg.vendor) 98463fa9f4cSJonathan Chen && q->type == CARDBUS_QUIRK_MAP_REG) { 98563fa9f4cSJonathan Chen cardbus_add_map(cbdev, child, q->arg1); 98663fa9f4cSJonathan Chen } 98763fa9f4cSJonathan Chen } 98863fa9f4cSJonathan Chen } 98963fa9f4cSJonathan Chen 9900c95c705SJonathan Chen int 99166e390feSWarner Losh cardbus_cis_read(device_t cbdev, device_t child, uint8_t id, 9920c95c705SJonathan Chen struct cis_tupleinfo **buff, int *nret) 9930c95c705SJonathan Chen { 9940c95c705SJonathan Chen struct tuple_callbacks cisread_callbacks[] = { 9950c95c705SJonathan Chen MAKETUPLE(NULL, nothing), 9960c95c705SJonathan Chen /* first entry will be overwritten */ 9970c95c705SJonathan Chen MAKETUPLE(NULL, nothing), 9980c95c705SJonathan Chen MAKETUPLE(DEVICE, nothing), 9990c95c705SJonathan Chen MAKETUPLE(LONG_LINK_CB, unhandled), 10000c95c705SJonathan Chen MAKETUPLE(INDIRECT, unhandled), 10010c95c705SJonathan Chen MAKETUPLE(CONFIG_CB, nothing), 10020c95c705SJonathan Chen MAKETUPLE(CFTABLE_ENTRY_CB, nothing), 10030c95c705SJonathan Chen MAKETUPLE(LONGLINK_MFC, unhandled), 10040c95c705SJonathan Chen MAKETUPLE(BAR, nothing), 10050c95c705SJonathan Chen MAKETUPLE(PWR_MGMNT, nothing), 10060c95c705SJonathan Chen MAKETUPLE(EXTDEVICE, nothing), 10070c95c705SJonathan Chen MAKETUPLE(CHECKSUM, nothing), 10080c95c705SJonathan Chen MAKETUPLE(LONGLINK_A, unhandled), 10090c95c705SJonathan Chen MAKETUPLE(LONGLINK_C, unhandled), 10100c95c705SJonathan Chen MAKETUPLE(LINKTARGET, nothing), 10110c95c705SJonathan Chen MAKETUPLE(NO_LINK, nothing), 10120c95c705SJonathan Chen MAKETUPLE(VERS_1, nothing), 10130c95c705SJonathan Chen MAKETUPLE(ALTSTR, nothing), 10140c95c705SJonathan Chen MAKETUPLE(DEVICE_A, nothing), 10150c95c705SJonathan Chen MAKETUPLE(JEDEC_C, nothing), 10160c95c705SJonathan Chen MAKETUPLE(JEDEC_A, nothing), 10170c95c705SJonathan Chen MAKETUPLE(CONFIG, nothing), 10180c95c705SJonathan Chen MAKETUPLE(CFTABLE_ENTRY, nothing), 10190c95c705SJonathan Chen MAKETUPLE(DEVICE_OC, nothing), 10200c95c705SJonathan Chen MAKETUPLE(DEVICE_OA, nothing), 10210c95c705SJonathan Chen MAKETUPLE(DEVICE_GEO, nothing), 10220c95c705SJonathan Chen MAKETUPLE(DEVICE_GEO_A, nothing), 10230c95c705SJonathan Chen MAKETUPLE(MANFID, nothing), 10240c95c705SJonathan Chen MAKETUPLE(FUNCID, nothing), 10250c95c705SJonathan Chen MAKETUPLE(FUNCE, nothing), 10260c95c705SJonathan Chen MAKETUPLE(SWIL, nothing), 10270c95c705SJonathan Chen MAKETUPLE(VERS_2, nothing), 10280c95c705SJonathan Chen MAKETUPLE(FORMAT, nothing), 10290c95c705SJonathan Chen MAKETUPLE(GEOMETRY, nothing), 10300c95c705SJonathan Chen MAKETUPLE(BYTEORDER, nothing), 10310c95c705SJonathan Chen MAKETUPLE(DATE, nothing), 10320c95c705SJonathan Chen MAKETUPLE(BATTERY, nothing), 10330c95c705SJonathan Chen MAKETUPLE(ORG, nothing), 10340c95c705SJonathan Chen MAKETUPLE(END, end), 10350c95c705SJonathan Chen MAKETUPLE(GENERIC, nothing), 10360c95c705SJonathan Chen }; 10370c95c705SJonathan Chen int ret; 10380c95c705SJonathan Chen 10390c95c705SJonathan Chen cisread_callbacks[0].id = id; 10400c95c705SJonathan Chen cisread_callbacks[0].name = "COPY"; 10410c95c705SJonathan Chen cisread_callbacks[0].func = decode_tuple_copy; 10420c95c705SJonathan Chen ncisread_buf = 0; 10430c95c705SJonathan Chen cisread_buf = NULL; 1044255b159fSJonathan Chen ret = cardbus_parse_cis(cbdev, child, cisread_callbacks); 10450c95c705SJonathan Chen 10460c95c705SJonathan Chen *buff = cisread_buf; 10470c95c705SJonathan Chen *nret = ncisread_buf; 1048a3133b58SWarner Losh return (ret); 10490c95c705SJonathan Chen } 10500c95c705SJonathan Chen 10510c95c705SJonathan Chen void 1052255b159fSJonathan Chen cardbus_cis_free(device_t cbdev, struct cis_tupleinfo *buff, int *nret) 10530c95c705SJonathan Chen { 10540c95c705SJonathan Chen int i; 10556f39832cSPeter Wemm for (i = 0; i < *nret; i++) 10560c95c705SJonathan Chen free(buff[i].data, M_DEVBUF); 10576f39832cSPeter Wemm if (*nret > 0) 10580c95c705SJonathan Chen free(buff, M_DEVBUF); 10590c95c705SJonathan Chen } 10600c95c705SJonathan Chen 10610c95c705SJonathan Chen int 1062255b159fSJonathan Chen cardbus_do_cis(device_t cbdev, device_t child) 10630c95c705SJonathan Chen { 106463fa9f4cSJonathan Chen int ret; 10650c95c705SJonathan Chen struct tuple_callbacks init_callbacks[] = { 10660c95c705SJonathan Chen MAKETUPLE(NULL, generic), 10670c95c705SJonathan Chen MAKETUPLE(DEVICE, generic), 10680c95c705SJonathan Chen MAKETUPLE(LONG_LINK_CB, unhandled), 10690c95c705SJonathan Chen MAKETUPLE(INDIRECT, unhandled), 10700c95c705SJonathan Chen MAKETUPLE(CONFIG_CB, generic), 10710c95c705SJonathan Chen MAKETUPLE(CFTABLE_ENTRY_CB, generic), 10720c95c705SJonathan Chen MAKETUPLE(LONGLINK_MFC, unhandled), 10730c95c705SJonathan Chen MAKETUPLE(BAR, bar), 10740c95c705SJonathan Chen MAKETUPLE(PWR_MGMNT, generic), 10750c95c705SJonathan Chen MAKETUPLE(EXTDEVICE, generic), 10760c95c705SJonathan Chen MAKETUPLE(CHECKSUM, generic), 10770c95c705SJonathan Chen MAKETUPLE(LONGLINK_A, unhandled), 10780c95c705SJonathan Chen MAKETUPLE(LONGLINK_C, unhandled), 10790c95c705SJonathan Chen MAKETUPLE(LINKTARGET, linktarget), 10800c95c705SJonathan Chen MAKETUPLE(NO_LINK, generic), 10810c95c705SJonathan Chen MAKETUPLE(VERS_1, vers_1), 10820c95c705SJonathan Chen MAKETUPLE(ALTSTR, generic), 10830c95c705SJonathan Chen MAKETUPLE(DEVICE_A, generic), 10840c95c705SJonathan Chen MAKETUPLE(JEDEC_C, generic), 10850c95c705SJonathan Chen MAKETUPLE(JEDEC_A, generic), 10860c95c705SJonathan Chen MAKETUPLE(CONFIG, generic), 10870c95c705SJonathan Chen MAKETUPLE(CFTABLE_ENTRY, generic), 10880c95c705SJonathan Chen MAKETUPLE(DEVICE_OC, generic), 10890c95c705SJonathan Chen MAKETUPLE(DEVICE_OA, generic), 10900c95c705SJonathan Chen MAKETUPLE(DEVICE_GEO, generic), 10910c95c705SJonathan Chen MAKETUPLE(DEVICE_GEO_A, generic), 10920c95c705SJonathan Chen MAKETUPLE(MANFID, manfid), 10930c95c705SJonathan Chen MAKETUPLE(FUNCID, funcid), 10940c95c705SJonathan Chen MAKETUPLE(FUNCE, funce), 10950c95c705SJonathan Chen MAKETUPLE(SWIL, generic), 10960c95c705SJonathan Chen MAKETUPLE(VERS_2, generic), 10970c95c705SJonathan Chen MAKETUPLE(FORMAT, generic), 10980c95c705SJonathan Chen MAKETUPLE(GEOMETRY, generic), 10990c95c705SJonathan Chen MAKETUPLE(BYTEORDER, generic), 11000c95c705SJonathan Chen MAKETUPLE(DATE, generic), 11010c95c705SJonathan Chen MAKETUPLE(BATTERY, generic), 11020c95c705SJonathan Chen MAKETUPLE(ORG, generic), 11030c95c705SJonathan Chen MAKETUPLE(END, end), 11040c95c705SJonathan Chen MAKETUPLE(GENERIC, generic), 11050c95c705SJonathan Chen }; 110663fa9f4cSJonathan Chen 110763fa9f4cSJonathan Chen ret = cardbus_parse_cis(cbdev, child, init_callbacks); 110863fa9f4cSJonathan Chen if (ret < 0) 1109a3133b58SWarner Losh return (ret); 111063fa9f4cSJonathan Chen cardbus_pickup_maps(cbdev, child); 1111a3133b58SWarner Losh return (cardbus_alloc_resources(cbdev, child)); 11120c95c705SJonathan Chen } 1113