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 */ 290db7e66cSJonathan Chen 30aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 31aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 32aad970f1SDavid E. O'Brien 330db7e66cSJonathan Chen /* 340db7e66cSJonathan Chen * CIS Handling for the Cardbus Bus 350db7e66cSJonathan Chen */ 360db7e66cSJonathan Chen 370db7e66cSJonathan Chen #include <sys/param.h> 380db7e66cSJonathan Chen #include <sys/systm.h> 390db7e66cSJonathan Chen #include <sys/kernel.h> 400c95c705SJonathan Chen #include <sys/malloc.h> 410db7e66cSJonathan Chen 420db7e66cSJonathan Chen #include <sys/bus.h> 430db7e66cSJonathan Chen #include <machine/bus.h> 440db7e66cSJonathan Chen #include <machine/resource.h> 450db7e66cSJonathan Chen #include <sys/rman.h> 461e962d00SScott Long #include <sys/endian.h> 470db7e66cSJonathan Chen 487ba175acSWarner Losh #include <sys/pciio.h> 4963fa9f4cSJonathan Chen #include <dev/pci/pcivar.h> 5063fa9f4cSJonathan Chen #include <dev/pci/pcireg.h> 510db7e66cSJonathan Chen 520db7e66cSJonathan Chen #include <dev/cardbus/cardbusreg.h> 5363fa9f4cSJonathan Chen #include <dev/cardbus/cardbusvar.h> 540db7e66cSJonathan Chen #include <dev/cardbus/cardbus_cis.h> 550db7e66cSJonathan Chen 5680f10018STakanori Watanabe #include <dev/pccard/pccardvar.h> 570c95c705SJonathan Chen 58b3889b68SWarner Losh extern int cardbus_cis_debug; 59b3889b68SWarner Losh 60b3889b68SWarner Losh #define DPRINTF(a) if (cardbus_cis_debug) printf a 61b3889b68SWarner Losh #define DEVPRINTF(x) if (cardbus_cis_debug) device_printf x 62b3889b68SWarner Losh 6322acd92bSWarner Losh struct tuple_callbacks; 6422acd92bSWarner Losh 6522acd92bSWarner Losh typedef int (tuple_cb) (device_t cbdev, device_t child, int id, int len, 6622acd92bSWarner Losh uint8_t *tupledata, uint32_t start, uint32_t *off, 6722acd92bSWarner Losh struct tuple_callbacks *info); 680db7e66cSJonathan Chen 690c95c705SJonathan Chen struct tuple_callbacks { 700c95c705SJonathan Chen int id; 710db7e66cSJonathan Chen char *name; 7222acd92bSWarner Losh tuple_cb *func; 730db7e66cSJonathan Chen }; 74255b159fSJonathan Chen 7522acd92bSWarner Losh static int decode_tuple_generic(device_t cbdev, device_t child, int id, 7622acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 7722acd92bSWarner Losh struct tuple_callbacks *info); 7822acd92bSWarner Losh static int decode_tuple_nothing(device_t cbdev, device_t child, int id, 7922acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 8022acd92bSWarner Losh struct tuple_callbacks *info); 8122acd92bSWarner Losh static int decode_tuple_copy(device_t cbdev, device_t child, int id, 8222acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 8322acd92bSWarner Losh struct tuple_callbacks *info); 8422acd92bSWarner Losh static int decode_tuple_linktarget(device_t cbdev, device_t child, int id, 8522acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 8622acd92bSWarner Losh struct tuple_callbacks *info); 8722acd92bSWarner Losh static int decode_tuple_vers_1(device_t cbdev, device_t child, int id, 8822acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 8922acd92bSWarner Losh struct tuple_callbacks *info); 9022acd92bSWarner Losh static int decode_tuple_funcid(device_t cbdev, device_t child, int id, 9122acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 9222acd92bSWarner Losh struct tuple_callbacks *info); 9322acd92bSWarner Losh static int decode_tuple_manfid(device_t cbdev, device_t child, int id, 9422acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 9522acd92bSWarner Losh struct tuple_callbacks *info); 9622acd92bSWarner Losh static int decode_tuple_funce(device_t cbdev, device_t child, int id, 9722acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 9822acd92bSWarner Losh struct tuple_callbacks *info); 9922acd92bSWarner Losh static int decode_tuple_bar(device_t cbdev, device_t child, int id, 10022acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 10122acd92bSWarner Losh struct tuple_callbacks *info); 10222acd92bSWarner Losh static int decode_tuple_unhandled(device_t cbdev, device_t child, int id, 10322acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 10422acd92bSWarner Losh struct tuple_callbacks *info); 10522acd92bSWarner Losh static int decode_tuple_end(device_t cbdev, device_t child, int id, 10622acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 10722acd92bSWarner Losh struct tuple_callbacks *info); 10822acd92bSWarner Losh 109255b159fSJonathan Chen static int cardbus_read_tuple_conf(device_t cbdev, device_t child, 11066e390feSWarner Losh uint32_t start, uint32_t *off, int *tupleid, int *len, 11166e390feSWarner Losh uint8_t *tupledata); 11263fa9f4cSJonathan Chen static int cardbus_read_tuple_mem(device_t cbdev, struct resource *res, 11366e390feSWarner Losh uint32_t start, uint32_t *off, int *tupleid, int *len, 11466e390feSWarner Losh uint8_t *tupledata); 115255b159fSJonathan Chen static int cardbus_read_tuple(device_t cbdev, device_t child, 11666e390feSWarner Losh struct resource *res, uint32_t start, uint32_t *off, 11766e390feSWarner Losh int *tupleid, int *len, uint8_t *tupledata); 11863fa9f4cSJonathan Chen static void cardbus_read_tuple_finish(device_t cbdev, device_t child, 11963fa9f4cSJonathan Chen int rid, struct resource *res); 12063fa9f4cSJonathan Chen static struct resource *cardbus_read_tuple_init(device_t cbdev, device_t child, 12166e390feSWarner Losh uint32_t *start, int *rid); 122255b159fSJonathan Chen static int decode_tuple(device_t cbdev, device_t child, int tupleid, 12366e390feSWarner Losh int len, uint8_t *tupledata, uint32_t start, 12466e390feSWarner Losh uint32_t *off, struct tuple_callbacks *callbacks); 125255b159fSJonathan Chen static int cardbus_parse_cis(device_t cbdev, device_t child, 126255b159fSJonathan Chen struct tuple_callbacks *callbacks); 12763fa9f4cSJonathan Chen static int barsort(const void *a, const void *b); 12863fa9f4cSJonathan Chen static int cardbus_alloc_resources(device_t cbdev, device_t child); 12963fa9f4cSJonathan Chen static void cardbus_add_map(device_t cbdev, device_t child, int reg); 13063fa9f4cSJonathan Chen static void cardbus_pickup_maps(device_t cbdev, device_t child); 13163fa9f4cSJonathan Chen 132255b159fSJonathan Chen 1330c95c705SJonathan Chen #define MAKETUPLE(NAME,FUNC) { CISTPL_ ## NAME, #NAME, decode_tuple_ ## FUNC } 1340db7e66cSJonathan Chen 1350db7e66cSJonathan Chen static char *funcnames[] = { 1360db7e66cSJonathan Chen "Multi-Functioned", 1370db7e66cSJonathan Chen "Memory", 1380db7e66cSJonathan Chen "Serial Port", 1390db7e66cSJonathan Chen "Parallel Port", 1400db7e66cSJonathan Chen "Fixed Disk", 1410db7e66cSJonathan Chen "Video Adaptor", 1420db7e66cSJonathan Chen "Network Adaptor", 1430db7e66cSJonathan Chen "AIMS", 1440db7e66cSJonathan Chen "SCSI", 1450db7e66cSJonathan Chen "Security" 1460db7e66cSJonathan Chen }; 1470db7e66cSJonathan Chen 14863fa9f4cSJonathan Chen struct cardbus_quirk { 14966e390feSWarner Losh uint32_t devid; /* Vendor/device of the card */ 15063fa9f4cSJonathan Chen int type; 15163fa9f4cSJonathan Chen #define CARDBUS_QUIRK_MAP_REG 1 /* PCI map register in weird place */ 15263fa9f4cSJonathan Chen int arg1; 15363fa9f4cSJonathan Chen int arg2; 15463fa9f4cSJonathan Chen }; 15563fa9f4cSJonathan Chen 15663fa9f4cSJonathan Chen struct cardbus_quirk cardbus_quirks[] = { 15763fa9f4cSJonathan Chen { 0 } 15863fa9f4cSJonathan Chen }; 15963fa9f4cSJonathan Chen 1600c95c705SJonathan Chen static struct cis_tupleinfo *cisread_buf; 1610c95c705SJonathan Chen static int ncisread_buf; 1620c95c705SJonathan Chen 163255b159fSJonathan Chen /* 164255b159fSJonathan Chen * Handler functions for various CIS tuples 165255b159fSJonathan Chen */ 166255b159fSJonathan Chen 16722acd92bSWarner Losh static int 16822acd92bSWarner Losh decode_tuple_generic(device_t cbdev, device_t child, int id, 16922acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 17022acd92bSWarner Losh struct tuple_callbacks *info) 1710db7e66cSJonathan Chen { 1720db7e66cSJonathan Chen int i; 1730db7e66cSJonathan Chen 17422acd92bSWarner Losh if (cardbus_cis_debug) { 1750db7e66cSJonathan Chen if (info) 1760db7e66cSJonathan Chen printf("TUPLE: %s [%d]:", info->name, len); 1770db7e66cSJonathan Chen else 1780db7e66cSJonathan Chen printf("TUPLE: Unknown(0x%02x) [%d]:", id, len); 1790db7e66cSJonathan Chen 1800db7e66cSJonathan Chen for (i = 0; i < len; i++) { 1810db7e66cSJonathan Chen if (i % 0x10 == 0 && len > 0x10) 1820db7e66cSJonathan Chen printf("\n 0x%02x:", i); 1837bec1dd5SJonathan Chen printf(" %02x", tupledata[i]); 1840db7e66cSJonathan Chen } 1850db7e66cSJonathan Chen printf("\n"); 18622acd92bSWarner Losh } 187a3133b58SWarner Losh return (0); 1880db7e66cSJonathan Chen } 1890db7e66cSJonathan Chen 19022acd92bSWarner Losh static int 19122acd92bSWarner Losh decode_tuple_nothing(device_t cbdev, device_t child, int id, 19222acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 19322acd92bSWarner Losh struct tuple_callbacks *info) 1940c95c705SJonathan Chen { 195a3133b58SWarner Losh return (0); 1960c95c705SJonathan Chen } 1970c95c705SJonathan Chen 19822acd92bSWarner Losh static int 19922acd92bSWarner Losh decode_tuple_copy(device_t cbdev, device_t child, int id, 20022acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 20122acd92bSWarner Losh struct tuple_callbacks *info) 2020c95c705SJonathan Chen { 2030c95c705SJonathan Chen struct cis_tupleinfo *tmpbuf; 2040c95c705SJonathan Chen 2050c95c705SJonathan Chen tmpbuf = malloc(sizeof(struct cis_tupleinfo) * (ncisread_buf+1), 206a163d034SWarner Losh M_DEVBUF, M_WAITOK); 2070c95c705SJonathan Chen if (ncisread_buf > 0) { 2080c95c705SJonathan Chen memcpy(tmpbuf, cisread_buf, 2090c95c705SJonathan Chen sizeof(struct cis_tupleinfo) * ncisread_buf); 2100c95c705SJonathan Chen free(cisread_buf, M_DEVBUF); 2110c95c705SJonathan Chen } 2120c95c705SJonathan Chen cisread_buf = tmpbuf; 2130c95c705SJonathan Chen 2140c95c705SJonathan Chen cisread_buf[ncisread_buf].id = id; 2150c95c705SJonathan Chen cisread_buf[ncisread_buf].len = len; 216a163d034SWarner Losh cisread_buf[ncisread_buf].data = malloc(len, M_DEVBUF, M_WAITOK); 2170c95c705SJonathan Chen memcpy(cisread_buf[ncisread_buf].data, tupledata, len); 2180c95c705SJonathan Chen ncisread_buf++; 219a3133b58SWarner Losh return (0); 2200c95c705SJonathan Chen } 2210c95c705SJonathan Chen 22222acd92bSWarner Losh static int 22322acd92bSWarner Losh decode_tuple_linktarget(device_t cbdev, device_t child, int id, 22422acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 22522acd92bSWarner Losh struct tuple_callbacks *info) 2260db7e66cSJonathan Chen { 22749f158ccSJonathan Chen int i; 22849f158ccSJonathan Chen 22922acd92bSWarner Losh if (cardbus_cis_debug) { 23049f158ccSJonathan Chen printf("TUPLE: %s [%d]:", info->name, len); 23149f158ccSJonathan Chen 23249f158ccSJonathan Chen for (i = 0; i < len; i++) { 23349f158ccSJonathan Chen if (i % 0x10 == 0 && len > 0x10) 23449f158ccSJonathan Chen printf("\n 0x%02x:", i); 23549f158ccSJonathan Chen printf(" %02x", tupledata[i]); 23649f158ccSJonathan Chen } 23749f158ccSJonathan Chen printf("\n"); 23822acd92bSWarner Losh } 2397bec1dd5SJonathan Chen if (len != 3 || tupledata[0] != 'C' || tupledata[1] != 'I' || 2407bec1dd5SJonathan Chen tupledata[2] != 'S') { 2410db7e66cSJonathan Chen printf("Invalid data for CIS Link Target!\n"); 242255b159fSJonathan Chen decode_tuple_generic(cbdev, child, id, len, tupledata, 24349f158ccSJonathan Chen start, off, info); 244a3133b58SWarner Losh return (EINVAL); 2450db7e66cSJonathan Chen } 246a3133b58SWarner Losh return (0); 2470db7e66cSJonathan Chen } 2480db7e66cSJonathan Chen 24922acd92bSWarner Losh static int 25022acd92bSWarner Losh decode_tuple_vers_1(device_t cbdev, device_t child, int id, 25122acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 25222acd92bSWarner Losh struct tuple_callbacks *info) 2530db7e66cSJonathan Chen { 2540db7e66cSJonathan Chen int i; 255fbe9cff1SWarner Losh 25622acd92bSWarner Losh if (cardbus_cis_debug) { 2577bec1dd5SJonathan Chen printf("Product version: %d.%d\n", tupledata[0], tupledata[1]); 2580db7e66cSJonathan Chen printf("Product name: "); 2590db7e66cSJonathan Chen for (i = 2; i < len; i++) { 2607bec1dd5SJonathan Chen if (tupledata[i] == '\0') 2610db7e66cSJonathan Chen printf(" | "); 2627bec1dd5SJonathan Chen else if (tupledata[i] == 0xff) 2630db7e66cSJonathan Chen break; 2640db7e66cSJonathan Chen else 2657bec1dd5SJonathan Chen printf("%c", tupledata[i]); 2660db7e66cSJonathan Chen } 2670db7e66cSJonathan Chen printf("\n"); 26822acd92bSWarner Losh } 269a3133b58SWarner Losh return (0); 2700db7e66cSJonathan Chen } 2710db7e66cSJonathan Chen 27222acd92bSWarner Losh static int 27322acd92bSWarner Losh decode_tuple_funcid(device_t cbdev, device_t child, int id, 27422acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 27522acd92bSWarner Losh struct tuple_callbacks *info) 2760db7e66cSJonathan Chen { 277fbe9cff1SWarner Losh struct cardbus_devinfo *dinfo = device_get_ivars(child); 2780db7e66cSJonathan Chen int numnames = sizeof(funcnames) / sizeof(funcnames[0]); 279fbe9cff1SWarner Losh int i; 2800db7e66cSJonathan Chen 28122acd92bSWarner Losh if (cardbus_cis_debug) { 2820db7e66cSJonathan Chen printf("Functions: "); 2830db7e66cSJonathan Chen for (i = 0; i < len; i++) { 2847bec1dd5SJonathan Chen if (tupledata[i] < numnames) 2857bec1dd5SJonathan Chen printf("%s", funcnames[tupledata[i]]); 2860db7e66cSJonathan Chen else 2877bec1dd5SJonathan Chen printf("Unknown(%d)", tupledata[i]); 288255b159fSJonathan Chen if (i < len-1) 289255b159fSJonathan Chen printf(", "); 2900db7e66cSJonathan Chen } 29122acd92bSWarner Losh printf("\n"); 29222acd92bSWarner Losh } 293fbe9cff1SWarner Losh if (len > 0) 294fbe9cff1SWarner Losh dinfo->funcid = tupledata[0]; /* use first in list */ 295a3133b58SWarner Losh return (0); 2960db7e66cSJonathan Chen } 2970db7e66cSJonathan Chen 29822acd92bSWarner Losh static int 29922acd92bSWarner Losh decode_tuple_manfid(device_t cbdev, device_t child, int id, 30022acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 30122acd92bSWarner Losh struct tuple_callbacks *info) 3020db7e66cSJonathan Chen { 303fbe9cff1SWarner Losh struct cardbus_devinfo *dinfo = device_get_ivars(child); 3040db7e66cSJonathan Chen int i; 305fbe9cff1SWarner Losh 30622acd92bSWarner Losh if (cardbus_cis_debug) { 3070db7e66cSJonathan Chen printf("Manufacturer ID: "); 3080db7e66cSJonathan Chen for (i = 0; i < len; i++) 3097bec1dd5SJonathan Chen printf("%02x", tupledata[i]); 3100db7e66cSJonathan Chen printf("\n"); 31122acd92bSWarner Losh } 312fbe9cff1SWarner Losh 313fbe9cff1SWarner Losh if (len == 5) { 314fbe9cff1SWarner Losh dinfo->mfrid = tupledata[1] | (tupledata[2] << 8); 315fbe9cff1SWarner Losh dinfo->prodid = tupledata[3] | (tupledata[4] << 8); 316fbe9cff1SWarner Losh } 317a3133b58SWarner Losh return (0); 3180db7e66cSJonathan Chen } 3190db7e66cSJonathan Chen 32022acd92bSWarner Losh static int 32122acd92bSWarner Losh decode_tuple_funce(device_t cbdev, device_t child, int id, 32222acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 32322acd92bSWarner Losh struct tuple_callbacks *info) 3240db7e66cSJonathan Chen { 325fbe9cff1SWarner Losh struct cardbus_devinfo *dinfo = device_get_ivars(child); 326fbe9cff1SWarner Losh int type, i; 327fbe9cff1SWarner Losh 32822acd92bSWarner Losh if (cardbus_cis_debug) { 3290db7e66cSJonathan Chen printf("Function Extension: "); 3300db7e66cSJonathan Chen for (i = 0; i < len; i++) 3317bec1dd5SJonathan Chen printf("%02x", tupledata[i]); 3320db7e66cSJonathan Chen printf("\n"); 33322acd92bSWarner Losh } 334fbe9cff1SWarner Losh if (len < 2) /* too short */ 335fbe9cff1SWarner Losh return (0); 336fbe9cff1SWarner Losh type = tupledata[0]; /* XXX <32 always? */ 337fbe9cff1SWarner Losh switch (dinfo->funcid) { 338fbe9cff1SWarner Losh case TPL_FUNC_SERIAL: 339fbe9cff1SWarner Losh if (type == TPL_FUNCE_SER_UART) { /* NB: len known > 1 */ 340fbe9cff1SWarner Losh dinfo->funce.sio.type = tupledata[1] & 0x1f; 341fbe9cff1SWarner Losh } 342fbe9cff1SWarner Losh dinfo->fepresent |= 1<<type; 343fbe9cff1SWarner Losh break; 344fbe9cff1SWarner Losh case TPL_FUNC_LAN: 345fbe9cff1SWarner Losh switch (type) { 346fbe9cff1SWarner Losh case TPL_FUNCE_LAN_TECH: 347fbe9cff1SWarner Losh dinfo->funce.lan.tech = tupledata[1]; /* XXX mask? */ 348fbe9cff1SWarner Losh break; 349fbe9cff1SWarner Losh #if 0 350fbe9cff1SWarner Losh case TPL_FUNCE_LAN_SPEED: 351fbe9cff1SWarner Losh for (i = 0; i < 3; i++) { 352fbe9cff1SWarner Losh if (dinfo->funce.lan.speed[i] == 0) { 353fbe9cff1SWarner Losh if (len > 4) { 354fbe9cff1SWarner Losh dinfo->funce.lan.speed[i] = 355fbe9cff1SWarner Losh ...; 356fbe9cff1SWarner Losh } 357fbe9cff1SWarner Losh break; 358fbe9cff1SWarner Losh } 359fbe9cff1SWarner Losh } 360fbe9cff1SWarner Losh break; 361fbe9cff1SWarner Losh #endif 362fbe9cff1SWarner Losh case TPL_FUNCE_LAN_MEDIA: 363fbe9cff1SWarner Losh for (i = 0; i < 4 && dinfo->funce.lan.media[i]; i++) { 364fbe9cff1SWarner Losh if (dinfo->funce.lan.media[i] == 0) { 365fbe9cff1SWarner Losh /* NB: len known > 1 */ 366fbe9cff1SWarner Losh dinfo->funce.lan.media[i] = 367fbe9cff1SWarner Losh tupledata[1]; /*XXX? mask */ 368fbe9cff1SWarner Losh break; 369fbe9cff1SWarner Losh } 370fbe9cff1SWarner Losh } 371fbe9cff1SWarner Losh break; 372fbe9cff1SWarner Losh case TPL_FUNCE_LAN_NID: 37322acd92bSWarner Losh if (tupledata[1] > sizeof(dinfo->funce.lan.nid)) { 37422acd92bSWarner Losh /* ignore, warning? */ 37522acd92bSWarner Losh return (0); 37622acd92bSWarner Losh } 37722acd92bSWarner Losh bcopy(tupledata + 2, dinfo->funce.lan.nid, 37822acd92bSWarner Losh tupledata[1]); 379fbe9cff1SWarner Losh break; 380fbe9cff1SWarner Losh case TPL_FUNCE_LAN_CONN: 381fbe9cff1SWarner Losh dinfo->funce.lan.contype = tupledata[1];/*XXX mask? */ 382fbe9cff1SWarner Losh break; 383fbe9cff1SWarner Losh } 384fbe9cff1SWarner Losh dinfo->fepresent |= 1<<type; 385fbe9cff1SWarner Losh break; 386fbe9cff1SWarner Losh } 387a3133b58SWarner Losh return (0); 3880db7e66cSJonathan Chen } 3890db7e66cSJonathan Chen 39022acd92bSWarner Losh static int 39122acd92bSWarner Losh decode_tuple_bar(device_t cbdev, device_t child, int id, 39222acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 39322acd92bSWarner Losh struct tuple_callbacks *info) 3940db7e66cSJonathan Chen { 39563fa9f4cSJonathan Chen struct cardbus_devinfo *dinfo = device_get_ivars(child); 3960db7e66cSJonathan Chen int type; 3971e962d00SScott Long uint8_t reg; 39872d3502eSScott Long uint32_t bar, pci_bar; 3990db7e66cSJonathan Chen 400e6e272b9SScott Long if (len != 6) { 4011e962d00SScott Long device_printf(cbdev, "CIS BAR length not 6 (%d)\n", len); 402e6e272b9SScott Long return (EINVAL); 403e6e272b9SScott Long } 4041e962d00SScott Long 4051e962d00SScott Long reg = *tupledata; 4061e962d00SScott Long len = le32toh(*(uint32_t*)(tupledata + 2)); 4070db7e66cSJonathan Chen if (reg & TPL_BAR_REG_AS) { 4080db7e66cSJonathan Chen type = SYS_RES_IOPORT; 4090db7e66cSJonathan Chen } else { 4100db7e66cSJonathan Chen type = SYS_RES_MEMORY; 4110db7e66cSJonathan Chen } 4121e962d00SScott Long 4131e962d00SScott Long bar = reg & TPL_BAR_REG_ASI_MASK; 4141e962d00SScott Long if (bar == 0) { 4151e962d00SScott Long device_printf(cbdev, "Invalid BAR type 0 in CIS\n"); 4161e962d00SScott Long return (EINVAL); /* XXX Return an error? */ 4171e962d00SScott Long } else if (bar == 7) { 4181e962d00SScott Long /* XXX Should we try to map in Option ROMs? */ 419a3133b58SWarner Losh return (0); 4200db7e66cSJonathan Chen } 4211e962d00SScott Long 42272d3502eSScott Long /* Convert from BAR type to BAR offset */ 4231e962d00SScott Long bar = CARDBUS_BASE0_REG + (bar - 1) * 4; 4241e962d00SScott Long 42563fa9f4cSJonathan Chen if (type == SYS_RES_MEMORY) { 42672d3502eSScott Long if (reg & TPL_BAR_REG_PREFETCHABLE) 42763fa9f4cSJonathan Chen dinfo->mprefetchable |= BARBIT(bar); 428f9aedaa4SWarner Losh #if 0 42972d3502eSScott Long if (reg & TPL_BAR_REG_BELOW1MB) 43063fa9f4cSJonathan Chen dinfo->mbelow1mb |= BARBIT(bar); 431f9aedaa4SWarner Losh #endif 4320db7e66cSJonathan Chen } 4331e962d00SScott Long 43472d3502eSScott Long /* 43572d3502eSScott Long * Sanity check the BAR length reported in the CIS with the length 43672d3502eSScott Long * encoded in the PCI BAR. The latter seems to be more reliable. 43772d3502eSScott Long * XXX - This probably belongs elsewhere. 43872d3502eSScott Long */ 43972d3502eSScott Long pci_write_config(child, bar, 0xffffffff, 4); 44072d3502eSScott Long pci_bar = pci_read_config(child, bar, 4); 44172d3502eSScott Long if ((pci_bar != 0x0) && (pci_bar != 0xffffffff)) { 44272d3502eSScott Long if (type == SYS_RES_MEMORY) { 44372d3502eSScott Long pci_bar &= ~0xf; 44472d3502eSScott Long } else { 44572d3502eSScott Long pci_bar &= ~0x3; 44672d3502eSScott Long } 44772d3502eSScott Long len = 1 << (ffs(pci_bar) - 1); 44872d3502eSScott Long } 44972d3502eSScott Long 450e6e272b9SScott Long DEVPRINTF((cbdev, "Opening BAR: type=%s, bar=%02x, len=%04x%s%s\n", 45163fa9f4cSJonathan Chen (type == SYS_RES_MEMORY) ? "MEM" : "IO", bar, len, 45263fa9f4cSJonathan Chen (type == SYS_RES_MEMORY && dinfo->mprefetchable & BARBIT(bar)) ? 453e6e272b9SScott Long " (Prefetchable)" : "", type == SYS_RES_MEMORY ? 4541e962d00SScott Long ((dinfo->mbelow1mb & BARBIT(bar)) ? " (Below 1Mb)" : "") : "")); 45563fa9f4cSJonathan Chen 4567ba175acSWarner Losh resource_list_add(&dinfo->pci.resources, type, bar, 0UL, ~0UL, len); 457e6e272b9SScott Long 4589fb92b64SScott Long /* 4599fb92b64SScott Long * Mark the appropriate bit in the PCI command register so that 46001f2fb65SWarner Losh * device drivers will know which type of BARs can be used. 4619fb92b64SScott Long */ 4629fb92b64SScott Long pci_enable_io(child, type); 463a3133b58SWarner Losh return (0); 4640db7e66cSJonathan Chen } 4650db7e66cSJonathan Chen 46622acd92bSWarner Losh static int 46722acd92bSWarner Losh decode_tuple_unhandled(device_t cbdev, device_t child, int id, 46822acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 46922acd92bSWarner Losh struct tuple_callbacks *info) 4700db7e66cSJonathan Chen { 47122acd92bSWarner Losh /* Make this message suck less XXX */ 4720db7e66cSJonathan Chen printf("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len); 473a3133b58SWarner Losh return (-1); 4740db7e66cSJonathan Chen } 4750db7e66cSJonathan Chen 47622acd92bSWarner Losh static int 47722acd92bSWarner Losh decode_tuple_end(device_t cbdev, device_t child, int id, 47822acd92bSWarner Losh int len, uint8_t *tupledata, uint32_t start, uint32_t *off, 47922acd92bSWarner Losh struct tuple_callbacks *info) 4800db7e66cSJonathan Chen { 48122acd92bSWarner Losh if (cardbus_cis_debug) { 4820c95c705SJonathan Chen printf("CIS reading done\n"); 48322acd92bSWarner Losh } 484a3133b58SWarner Losh return (0); 4850db7e66cSJonathan Chen } 4860db7e66cSJonathan Chen 487255b159fSJonathan Chen /* 488255b159fSJonathan Chen * Functions to read the a tuple from the card 489255b159fSJonathan Chen */ 490255b159fSJonathan Chen 4910db7e66cSJonathan Chen static int 49266e390feSWarner Losh cardbus_read_tuple_conf(device_t cbdev, device_t child, uint32_t start, 49366e390feSWarner Losh uint32_t *off, int *tupleid, int *len, uint8_t *tupledata) 4947bec1dd5SJonathan Chen { 4957bec1dd5SJonathan Chen int i, j; 49666e390feSWarner Losh uint32_t e; 49766e390feSWarner Losh uint32_t loc; 4987bec1dd5SJonathan Chen 49963fa9f4cSJonathan Chen loc = start + *off; 50049f158ccSJonathan Chen 50149f158ccSJonathan Chen e = pci_read_config(child, loc - loc % 4, 4); 50249f158ccSJonathan Chen for (j = loc % 4; j > 0; j--) 5037bec1dd5SJonathan Chen e >>= 8; 5047bec1dd5SJonathan Chen *len = 0; 50549f158ccSJonathan Chen for (i = loc, j = -2; j < *len; j++, i++) { 5067bec1dd5SJonathan Chen if (i % 4 == 0) 5077bec1dd5SJonathan Chen e = pci_read_config(child, i, 4); 5087bec1dd5SJonathan Chen if (j == -2) 5097bec1dd5SJonathan Chen *tupleid = 0xff & e; 5107bec1dd5SJonathan Chen else if (j == -1) 5117bec1dd5SJonathan Chen *len = 0xff & e; 5127bec1dd5SJonathan Chen else 5137bec1dd5SJonathan Chen tupledata[j] = 0xff & e; 5147bec1dd5SJonathan Chen e >>= 8; 5157bec1dd5SJonathan Chen } 5167bec1dd5SJonathan Chen *off += *len + 2; 517a3133b58SWarner Losh return (0); 5187bec1dd5SJonathan Chen } 5197bec1dd5SJonathan Chen 5207bec1dd5SJonathan Chen static int 52166e390feSWarner Losh cardbus_read_tuple_mem(device_t cbdev, struct resource *res, uint32_t start, 52266e390feSWarner Losh uint32_t *off, int *tupleid, int *len, uint8_t *tupledata) 5230db7e66cSJonathan Chen { 52463fa9f4cSJonathan Chen bus_space_tag_t bt; 52563fa9f4cSJonathan Chen bus_space_handle_t bh; 52663fa9f4cSJonathan Chen int ret; 5270db7e66cSJonathan Chen 52863fa9f4cSJonathan Chen bt = rman_get_bustag(res); 52963fa9f4cSJonathan Chen bh = rman_get_bushandle(res); 5300db7e66cSJonathan Chen 53163fa9f4cSJonathan Chen *tupleid = bus_space_read_1(bt, bh, start + *off); 53263fa9f4cSJonathan Chen *len = bus_space_read_1(bt, bh, start + *off + 1); 53363fa9f4cSJonathan Chen bus_space_read_region_1(bt, bh, *off + start + 2, tupledata, *len); 53463fa9f4cSJonathan Chen ret = 0; 53563fa9f4cSJonathan Chen *off += *len + 2; 536a3133b58SWarner Losh return (ret); 5370db7e66cSJonathan Chen } 53863fa9f4cSJonathan Chen 53963fa9f4cSJonathan Chen static int 54063fa9f4cSJonathan Chen cardbus_read_tuple(device_t cbdev, device_t child, struct resource *res, 54166e390feSWarner Losh uint32_t start, uint32_t *off, int *tupleid, int *len, 54266e390feSWarner Losh uint8_t *tupledata) 54363fa9f4cSJonathan Chen { 54463fa9f4cSJonathan Chen if (res == (struct resource*)~0UL) { 545a3133b58SWarner Losh return (cardbus_read_tuple_conf(cbdev, child, start, off, 546a3133b58SWarner Losh tupleid, len, tupledata)); 54763fa9f4cSJonathan Chen } else { 548a3133b58SWarner Losh return (cardbus_read_tuple_mem(cbdev, res, start, off, 549a3133b58SWarner Losh tupleid, len, tupledata)); 55063fa9f4cSJonathan Chen } 55163fa9f4cSJonathan Chen } 55263fa9f4cSJonathan Chen 55363fa9f4cSJonathan Chen static void 55463fa9f4cSJonathan Chen cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid, 55563fa9f4cSJonathan Chen struct resource *res) 55663fa9f4cSJonathan Chen { 55763fa9f4cSJonathan Chen if (res != (struct resource*)~0UL) { 55863fa9f4cSJonathan Chen bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res); 55963fa9f4cSJonathan Chen pci_write_config(child, rid, 0, 4); 56063fa9f4cSJonathan Chen PCI_DISABLE_IO(cbdev, child, SYS_RES_MEMORY); 56163fa9f4cSJonathan Chen } 56263fa9f4cSJonathan Chen } 56363fa9f4cSJonathan Chen 56463fa9f4cSJonathan Chen static struct resource * 56566e390feSWarner Losh cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start, 56663fa9f4cSJonathan Chen int *rid) 56763fa9f4cSJonathan Chen { 56866e390feSWarner Losh uint32_t testval; 56966e390feSWarner Losh uint32_t size; 57063fa9f4cSJonathan Chen struct resource *res; 57163fa9f4cSJonathan Chen 57263fa9f4cSJonathan Chen switch (CARDBUS_CIS_SPACE(*start)) { 57363fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_TUPLE: 574e6e272b9SScott Long /* CIS in PCI config space need no initialization */ 57521677473SWarner Losh return ((struct resource*)~0UL); 57663fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR0: 57763fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR1: 57863fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR2: 57963fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR3: 58063fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR4: 58163fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR5: 58263fa9f4cSJonathan Chen *rid = CARDBUS_BASE0_REG + (CARDBUS_CIS_SPACE(*start) - 1) * 4; 58363fa9f4cSJonathan Chen break; 58463fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_ROM: 58563fa9f4cSJonathan Chen *rid = CARDBUS_ROM_REG; 586e6e272b9SScott Long #if 0 587e6e272b9SScott Long /* 588e6e272b9SScott Long * This mask doesn't contain the bit that actually enables 589e6e272b9SScott Long * the Option ROM. 590e6e272b9SScott Long */ 59163fa9f4cSJonathan Chen pci_write_config(child, *rid, CARDBUS_ROM_ADDRMASK, 4); 592e6e272b9SScott Long #endif 59363fa9f4cSJonathan Chen break; 59463fa9f4cSJonathan Chen default: 59563fa9f4cSJonathan Chen device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n", 59663fa9f4cSJonathan Chen CARDBUS_CIS_SPACE(*start)); 597a3133b58SWarner Losh return (NULL); 59863fa9f4cSJonathan Chen } 59963fa9f4cSJonathan Chen 60063fa9f4cSJonathan Chen /* figure out how much space we need */ 601e6e272b9SScott Long pci_write_config(child, *rid, 0xffffffff, 4); 60263fa9f4cSJonathan Chen testval = pci_read_config(child, *rid, 4); 603e6e272b9SScott Long 604e6e272b9SScott Long /* 605e6e272b9SScott Long * This bit has a different meaning depending if we are dealing 6061e06ae99SScott Long * with a normal BAR or an Option ROM BAR. 607e6e272b9SScott Long */ 608e6e272b9SScott Long if (((testval & 0x1) == 0x1) && (*rid != CARDBUS_ROM_REG)) { 60963fa9f4cSJonathan Chen device_printf(cbdev, "CIS Space is IO, expecting memory.\n"); 610a3133b58SWarner Losh return (NULL); 61163fa9f4cSJonathan Chen } 612e6e272b9SScott Long 61363fa9f4cSJonathan Chen size = CARDBUS_MAPREG_MEM_SIZE(testval); 614e6e272b9SScott Long /* XXX Is this some kind of hack? */ 61563fa9f4cSJonathan Chen if (size < 4096) 61663fa9f4cSJonathan Chen size = 4096; 61763fa9f4cSJonathan Chen /* allocate the memory space to read CIS */ 61863fa9f4cSJonathan Chen res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, rid, 0, ~0, size, 61963fa9f4cSJonathan Chen rman_make_alignment_flags(size) | RF_ACTIVE); 62063fa9f4cSJonathan Chen if (res == NULL) { 62163fa9f4cSJonathan Chen device_printf(cbdev, "Unable to allocate resource " 62263fa9f4cSJonathan Chen "to read CIS.\n"); 623a3133b58SWarner Losh return (NULL); 62463fa9f4cSJonathan Chen } 62563fa9f4cSJonathan Chen pci_write_config(child, *rid, 62663fa9f4cSJonathan Chen rman_get_start(res) | ((*rid == CARDBUS_ROM_REG)? 62763fa9f4cSJonathan Chen CARDBUS_ROM_ENABLE : 0), 62863fa9f4cSJonathan Chen 4); 62963fa9f4cSJonathan Chen PCI_ENABLE_IO(cbdev, child, SYS_RES_MEMORY); 63063fa9f4cSJonathan Chen 63163fa9f4cSJonathan Chen /* Flip to the right ROM image if CIS is in ROM */ 63263fa9f4cSJonathan Chen if (CARDBUS_CIS_SPACE(*start) == CARDBUS_CIS_ASI_ROM) { 63363fa9f4cSJonathan Chen bus_space_tag_t bt; 63463fa9f4cSJonathan Chen bus_space_handle_t bh; 63566e390feSWarner Losh uint32_t imagesize; 63666e390feSWarner Losh uint32_t imagebase = 0; 63766e390feSWarner Losh uint32_t pcidata; 63866e390feSWarner Losh uint16_t romsig; 63963fa9f4cSJonathan Chen int romnum = 0; 640e6e272b9SScott Long int imagenum; 64163fa9f4cSJonathan Chen 64263fa9f4cSJonathan Chen bt = rman_get_bustag(res); 64363fa9f4cSJonathan Chen bh = rman_get_bushandle(res); 64463fa9f4cSJonathan Chen 64563fa9f4cSJonathan Chen imagenum = CARDBUS_CIS_ASI_ROM_IMAGE(*start); 64663fa9f4cSJonathan Chen for (romnum = 0;; romnum++) { 647e6e272b9SScott Long romsig = bus_space_read_2(bt, bh, 648e6e272b9SScott Long imagebase + CARDBUS_EXROM_SIGNATURE); 649e6e272b9SScott Long if (romsig != 0xaa55) { 65063fa9f4cSJonathan Chen device_printf(cbdev, "Bad header in rom %d: " 651e6e272b9SScott Long "[%x] %04x\n", romnum, imagebase + 652e6e272b9SScott Long CARDBUS_EXROM_SIGNATURE, romsig); 65363fa9f4cSJonathan Chen bus_release_resource(cbdev, SYS_RES_MEMORY, 65463fa9f4cSJonathan Chen *rid, res); 65563fa9f4cSJonathan Chen *rid = 0; 656a3133b58SWarner Losh return (NULL); 65763fa9f4cSJonathan Chen } 658e6e272b9SScott Long 659e6e272b9SScott Long /* 660e6e272b9SScott Long * If this was the Option ROM image that we were 661e6e272b9SScott Long * looking for, then we are done. 662e6e272b9SScott Long */ 663e6e272b9SScott Long if (romnum == imagenum) 664e6e272b9SScott Long break; 665e6e272b9SScott Long 666e6e272b9SScott Long /* Find out where the next Option ROM image is */ 667e6e272b9SScott Long pcidata = imagebase + bus_space_read_2(bt, bh, 668e6e272b9SScott Long imagebase + CARDBUS_EXROM_DATA_PTR); 66963fa9f4cSJonathan Chen imagesize = bus_space_read_2(bt, bh, 670e6e272b9SScott Long pcidata + CARDBUS_EXROM_DATA_IMAGE_LENGTH); 6710db7e66cSJonathan Chen 6727bec1dd5SJonathan Chen if (imagesize == 0) { 6730db7e66cSJonathan Chen /* 6740db7e66cSJonathan Chen * XXX some ROMs seem to have this as zero, 6750db7e66cSJonathan Chen * can we assume this means 1 block? 6760db7e66cSJonathan Chen */ 677e6e272b9SScott Long device_printf(cbdev, "Warning, size of Option " 678e6e272b9SScott Long "ROM image %d is 0 bytes, assuming 512 " 679e6e272b9SScott Long "bytes.\n", romnum); 6800db7e66cSJonathan Chen imagesize = 1; 6817bec1dd5SJonathan Chen } 682e6e272b9SScott Long 683e6e272b9SScott Long /* Image size is in 512 byte units */ 6840db7e66cSJonathan Chen imagesize <<= 9; 6850db7e66cSJonathan Chen 686e6e272b9SScott Long if ((bus_space_read_1(bt, bh, pcidata + 6871e06ae99SScott Long CARDBUS_EXROM_DATA_INDICATOR) & 0x80) != 0) { 688e6e272b9SScott Long device_printf(cbdev, "Cannot find CIS in " 689e6e272b9SScott Long "Option ROM\n"); 690e6e272b9SScott Long bus_release_resource(cbdev, SYS_RES_MEMORY, 691e6e272b9SScott Long *rid, res); 692e6e272b9SScott Long *rid = 0; 693a3133b58SWarner Losh return (NULL); 6940db7e66cSJonathan Chen } 695e6e272b9SScott Long imagebase += imagesize; 6960db7e66cSJonathan Chen } 697e6e272b9SScott Long *start = imagebase + CARDBUS_CIS_ADDR(*start); 6980db7e66cSJonathan Chen } else { 699e6e272b9SScott Long *start = CARDBUS_CIS_ADDR(*start); 7000db7e66cSJonathan Chen } 701e6e272b9SScott Long 702a3133b58SWarner Losh return (res); 7037bec1dd5SJonathan Chen } 7047bec1dd5SJonathan Chen 705255b159fSJonathan Chen /* 706255b159fSJonathan Chen * Dispatch the right handler function per tuple 707255b159fSJonathan Chen */ 708255b159fSJonathan Chen 7097bec1dd5SJonathan Chen static int 710255b159fSJonathan Chen decode_tuple(device_t cbdev, device_t child, int tupleid, int len, 71166e390feSWarner Losh uint8_t *tupledata, uint32_t start, uint32_t *off, 7120c95c705SJonathan Chen struct tuple_callbacks *callbacks) 7137bec1dd5SJonathan Chen { 7147bec1dd5SJonathan Chen int i; 7150c95c705SJonathan Chen for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) { 7160c95c705SJonathan Chen if (tupleid == callbacks[i].id) 717a3133b58SWarner Losh return (callbacks[i].func(cbdev, child, tupleid, len, 718a3133b58SWarner Losh tupledata, start, off, &callbacks[i])); 7197bec1dd5SJonathan Chen } 7207bec1dd5SJonathan Chen 72149f158ccSJonathan Chen if (tupleid < CISTPL_CUSTOMSTART) { 722255b159fSJonathan Chen device_printf(cbdev, "Undefined tuple encountered, " 723255b159fSJonathan Chen "CIS parsing terminated\n"); 724a3133b58SWarner Losh return (EINVAL); 72549f158ccSJonathan Chen } 726a3133b58SWarner Losh return (callbacks[i].func(cbdev, child, tupleid, len, 727a3133b58SWarner Losh tupledata, start, off, NULL)); 7280db7e66cSJonathan Chen } 7290db7e66cSJonathan Chen 7300c95c705SJonathan Chen static int 731255b159fSJonathan Chen cardbus_parse_cis(device_t cbdev, device_t child, 7320c95c705SJonathan Chen struct tuple_callbacks *callbacks) 7330db7e66cSJonathan Chen { 73466e390feSWarner Losh uint8_t tupledata[MAXTUPLESIZE]; 7357bec1dd5SJonathan Chen int tupleid; 7367bec1dd5SJonathan Chen int len; 7377bec1dd5SJonathan Chen int expect_linktarget; 73866e390feSWarner Losh uint32_t start, off; 73963fa9f4cSJonathan Chen struct resource *res; 74063fa9f4cSJonathan Chen int rid; 7410db7e66cSJonathan Chen 7420db7e66cSJonathan Chen bzero(tupledata, MAXTUPLESIZE); 7437bec1dd5SJonathan Chen expect_linktarget = TRUE; 744e6e272b9SScott Long if ((start = pci_read_config(child, CARDBUS_CIS_REG, 4)) == 0) 745e6e272b9SScott Long return (ENXIO); 74649f158ccSJonathan Chen off = 0; 74763fa9f4cSJonathan Chen res = cardbus_read_tuple_init(cbdev, child, &start, &rid); 74863fa9f4cSJonathan Chen if (res == NULL) 749a3133b58SWarner Losh return (ENXIO); 7501e962d00SScott Long 7517bec1dd5SJonathan Chen do { 75263fa9f4cSJonathan Chen if (0 != cardbus_read_tuple(cbdev, child, res, start, &off, 75363fa9f4cSJonathan Chen &tupleid, &len, tupledata)) { 75463fa9f4cSJonathan Chen device_printf(cbdev, "Failed to read CIS.\n"); 75563fa9f4cSJonathan Chen cardbus_read_tuple_finish(cbdev, child, rid, res); 756a3133b58SWarner Losh return (ENXIO); 75763fa9f4cSJonathan Chen } 7587bec1dd5SJonathan Chen 7597bec1dd5SJonathan Chen if (expect_linktarget && tupleid != CISTPL_LINKTARGET) { 760255b159fSJonathan Chen device_printf(cbdev, "Expecting link target, got 0x%x\n", 7617bec1dd5SJonathan Chen tupleid); 76263fa9f4cSJonathan Chen cardbus_read_tuple_finish(cbdev, child, rid, res); 763a3133b58SWarner Losh return (EINVAL); 7647bec1dd5SJonathan Chen } 765255b159fSJonathan Chen expect_linktarget = decode_tuple(cbdev, child, tupleid, len, 76663fa9f4cSJonathan Chen tupledata, start, &off, callbacks); 76763fa9f4cSJonathan Chen if (expect_linktarget != 0) { 76863fa9f4cSJonathan Chen cardbus_read_tuple_finish(cbdev, child, rid, res); 769a3133b58SWarner Losh return (expect_linktarget); 77063fa9f4cSJonathan Chen } 7717bec1dd5SJonathan Chen } while (tupleid != CISTPL_END); 77263fa9f4cSJonathan Chen cardbus_read_tuple_finish(cbdev, child, rid, res); 773a3133b58SWarner Losh return (0); 7740db7e66cSJonathan Chen } 7750db7e66cSJonathan Chen 77651715fe7SWarner Losh static void 77751715fe7SWarner Losh cardbus_do_res(struct resource_list_entry *rle, device_t child, uint32_t start) 77851715fe7SWarner Losh { 77951715fe7SWarner Losh rle->start = start; 78051715fe7SWarner Losh rle->end = start + rle->count - 1; 78151715fe7SWarner Losh pci_write_config(child, rle->rid, rle->start, 4); 78251715fe7SWarner Losh } 78351715fe7SWarner Losh 78463fa9f4cSJonathan Chen static int 78563fa9f4cSJonathan Chen barsort(const void *a, const void *b) 78663fa9f4cSJonathan Chen { 78778b226dcSAlfred Perlstein return ((*(const struct resource_list_entry * const *)b)->count - 78878b226dcSAlfred Perlstein (*(const struct resource_list_entry * const *)a)->count); 78963fa9f4cSJonathan Chen } 79063fa9f4cSJonathan Chen 79163fa9f4cSJonathan Chen static int 79263fa9f4cSJonathan Chen cardbus_alloc_resources(device_t cbdev, device_t child) 79363fa9f4cSJonathan Chen { 79463fa9f4cSJonathan Chen struct cardbus_devinfo *dinfo = device_get_ivars(child); 79563fa9f4cSJonathan Chen int count; 79663fa9f4cSJonathan Chen struct resource_list_entry *rle; 79763fa9f4cSJonathan Chen struct resource_list_entry **barlist; 79863fa9f4cSJonathan Chen int tmp; 79966e390feSWarner Losh uint32_t mem_psize = 0, mem_nsize = 0, io_size = 0; 80063fa9f4cSJonathan Chen struct resource *res; 80166e390feSWarner Losh uint32_t start,end; 80221677473SWarner Losh int rid, flags; 80363fa9f4cSJonathan Chen 80463fa9f4cSJonathan Chen count = 0; 80521677473SWarner Losh SLIST_FOREACH(rle, &dinfo->pci.resources, link) { 80663fa9f4cSJonathan Chen count++; 80721677473SWarner Losh } 80863fa9f4cSJonathan Chen if (count == 0) 809a3133b58SWarner Losh return (0); 81063fa9f4cSJonathan Chen barlist = malloc(sizeof(struct resource_list_entry*) * count, M_DEVBUF, 811a163d034SWarner Losh M_WAITOK); 81263fa9f4cSJonathan Chen count = 0; 81321677473SWarner Losh SLIST_FOREACH(rle, &dinfo->pci.resources, link) { 81463fa9f4cSJonathan Chen barlist[count] = rle; 81563fa9f4cSJonathan Chen if (rle->type == SYS_RES_IOPORT) { 81663fa9f4cSJonathan Chen io_size += rle->count; 81763fa9f4cSJonathan Chen } else if (rle->type == SYS_RES_MEMORY) { 81863fa9f4cSJonathan Chen if (dinfo->mprefetchable & BARBIT(rle->rid)) 81963fa9f4cSJonathan Chen mem_psize += rle->count; 82063fa9f4cSJonathan Chen else 82163fa9f4cSJonathan Chen mem_nsize += rle->count; 82263fa9f4cSJonathan Chen } 82363fa9f4cSJonathan Chen count++; 82463fa9f4cSJonathan Chen } 82563fa9f4cSJonathan Chen 82663fa9f4cSJonathan Chen /* 82763fa9f4cSJonathan Chen * We want to allocate the largest resource first, so that our 82863fa9f4cSJonathan Chen * allocated memory is packed. 82963fa9f4cSJonathan Chen */ 83063fa9f4cSJonathan Chen qsort(barlist, count, sizeof(struct resource_list_entry*), barsort); 83163fa9f4cSJonathan Chen 83263fa9f4cSJonathan Chen /* Allocate prefetchable memory */ 83363fa9f4cSJonathan Chen flags = 0; 83463fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 83551715fe7SWarner Losh rle = barlist[tmp]; 83651715fe7SWarner Losh if (rle->res == NULL && 83751715fe7SWarner Losh rle->type == SYS_RES_MEMORY && 83851715fe7SWarner Losh dinfo->mprefetchable & BARBIT(rle->rid)) { 83951715fe7SWarner Losh flags = rman_make_alignment_flags(rle->count); 84063fa9f4cSJonathan Chen break; 84163fa9f4cSJonathan Chen } 84263fa9f4cSJonathan Chen } 84363fa9f4cSJonathan Chen if (flags > 0) { /* If any prefetchable memory is requested... */ 84463fa9f4cSJonathan Chen /* 84563fa9f4cSJonathan Chen * First we allocate one big space for all resources of this 84663fa9f4cSJonathan Chen * type. We do this because our parent, pccbb, needs to open 84763fa9f4cSJonathan Chen * a window to forward all addresses within the window, and 84863fa9f4cSJonathan Chen * it would be best if nobody else has resources allocated 84963fa9f4cSJonathan Chen * within the window. 85063fa9f4cSJonathan Chen * (XXX: Perhaps there might be a better way to do this?) 85163fa9f4cSJonathan Chen */ 85263fa9f4cSJonathan Chen rid = 0; 85363fa9f4cSJonathan Chen res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0, 85463fa9f4cSJonathan Chen (dinfo->mprefetchable & dinfo->mbelow1mb)?0xFFFFF:~0UL, 85563fa9f4cSJonathan Chen mem_psize, flags); 8566d9fcd03SWarner Losh if (res == NULL) { 8576d9fcd03SWarner Losh device_printf(cbdev, 8586d9fcd03SWarner Losh "Can't get memory for prefetch mem\n"); 859b44f8087SPoul-Henning Kamp free(barlist, M_DEVBUF); 8606d9fcd03SWarner Losh return (EIO); 8616d9fcd03SWarner Losh } 86263fa9f4cSJonathan Chen start = rman_get_start(res); 86363fa9f4cSJonathan Chen end = rman_get_end(res); 86463fa9f4cSJonathan Chen DEVPRINTF((cbdev, "Prefetchable memory at %x-%x\n", start, end)); 86563fa9f4cSJonathan Chen /* 86663fa9f4cSJonathan Chen * Now that we know the region is free, release it and hand it 86763fa9f4cSJonathan Chen * out piece by piece. 86863fa9f4cSJonathan Chen */ 86963fa9f4cSJonathan Chen bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res); 87063fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 87151715fe7SWarner Losh rle = barlist[tmp]; 87251715fe7SWarner Losh if (rle->type == SYS_RES_MEMORY && 87351715fe7SWarner Losh dinfo->mprefetchable & BARBIT(rle->rid)) { 87451715fe7SWarner Losh cardbus_do_res(rle, child, start); 87551715fe7SWarner Losh start += rle->count; 87663fa9f4cSJonathan Chen } 87763fa9f4cSJonathan Chen } 87821677473SWarner Losh } 87963fa9f4cSJonathan Chen 88063fa9f4cSJonathan Chen /* Allocate non-prefetchable memory */ 88163fa9f4cSJonathan Chen flags = 0; 88263fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 88351715fe7SWarner Losh rle = barlist[tmp]; 88451715fe7SWarner Losh if (rle->type == SYS_RES_MEMORY && 88551715fe7SWarner Losh (dinfo->mprefetchable & BARBIT(rle->rid)) == 0) { 88651715fe7SWarner Losh flags = rman_make_alignment_flags(rle->count); 88763fa9f4cSJonathan Chen break; 88863fa9f4cSJonathan Chen } 88963fa9f4cSJonathan Chen } 89063fa9f4cSJonathan Chen if (flags > 0) { /* If any non-prefetchable memory is requested... */ 89163fa9f4cSJonathan Chen /* 89263fa9f4cSJonathan Chen * First we allocate one big space for all resources of this 89363fa9f4cSJonathan Chen * type. We do this because our parent, pccbb, needs to open 89463fa9f4cSJonathan Chen * a window to forward all addresses within the window, and 89563fa9f4cSJonathan Chen * it would be best if nobody else has resources allocated 89663fa9f4cSJonathan Chen * within the window. 89763fa9f4cSJonathan Chen * (XXX: Perhaps there might be a better way to do this?) 89863fa9f4cSJonathan Chen */ 89963fa9f4cSJonathan Chen rid = 0; 90063fa9f4cSJonathan Chen res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0, 90163fa9f4cSJonathan Chen ((~dinfo->mprefetchable) & dinfo->mbelow1mb)?0xFFFFF:~0UL, 90263fa9f4cSJonathan Chen mem_nsize, flags); 9036d9fcd03SWarner Losh if (res == NULL) { 9046d9fcd03SWarner Losh device_printf(cbdev, 9056d9fcd03SWarner Losh "Can't get memory for non-prefetch mem\n"); 906b44f8087SPoul-Henning Kamp free(barlist, M_DEVBUF); 9076d9fcd03SWarner Losh return (EIO); 9086d9fcd03SWarner Losh } 90963fa9f4cSJonathan Chen start = rman_get_start(res); 91063fa9f4cSJonathan Chen end = rman_get_end(res); 91163fa9f4cSJonathan Chen DEVPRINTF((cbdev, "Non-prefetchable memory at %x-%x\n", 91263fa9f4cSJonathan Chen start, end)); 91363fa9f4cSJonathan Chen /* 91463fa9f4cSJonathan Chen * Now that we know the region is free, release it and hand it 91563fa9f4cSJonathan Chen * out piece by piece. 91663fa9f4cSJonathan Chen */ 91763fa9f4cSJonathan Chen bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res); 91863fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 91951715fe7SWarner Losh rle = barlist[tmp]; 92051715fe7SWarner Losh if (rle->type == SYS_RES_MEMORY && 92151715fe7SWarner Losh (dinfo->mprefetchable & BARBIT(rle->rid)) == 0) { 92251715fe7SWarner Losh cardbus_do_res(rle, child, start); 92351715fe7SWarner Losh start += rle->count; 92463fa9f4cSJonathan Chen } 92563fa9f4cSJonathan Chen } 92663fa9f4cSJonathan Chen } 92763fa9f4cSJonathan Chen 92863fa9f4cSJonathan Chen /* Allocate IO ports */ 92963fa9f4cSJonathan Chen flags = 0; 93063fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 93151715fe7SWarner Losh rle = barlist[tmp]; 93251715fe7SWarner Losh if (rle->type == SYS_RES_IOPORT) { 93351715fe7SWarner Losh flags = rman_make_alignment_flags(rle->count); 93463fa9f4cSJonathan Chen break; 93563fa9f4cSJonathan Chen } 93663fa9f4cSJonathan Chen } 93763fa9f4cSJonathan Chen if (flags > 0) { /* If any IO port is requested... */ 93863fa9f4cSJonathan Chen /* 93963fa9f4cSJonathan Chen * First we allocate one big space for all resources of this 94063fa9f4cSJonathan Chen * type. We do this because our parent, pccbb, needs to open 94163fa9f4cSJonathan Chen * a window to forward all addresses within the window, and 94263fa9f4cSJonathan Chen * it would be best if nobody else has resources allocated 94363fa9f4cSJonathan Chen * within the window. 94463fa9f4cSJonathan Chen * (XXX: Perhaps there might be a better way to do this?) 94563fa9f4cSJonathan Chen */ 94663fa9f4cSJonathan Chen rid = 0; 94721677473SWarner Losh res = bus_alloc_resource(cbdev, SYS_RES_IOPORT, &rid, 0, 94821677473SWarner Losh (dinfo->ibelow1mb)?0xFFFFF:~0UL, io_size, flags); 9496d9fcd03SWarner Losh if (res == NULL) { 9506d9fcd03SWarner Losh device_printf(cbdev, 9516d9fcd03SWarner Losh "Can't get memory for IO ports\n"); 952b44f8087SPoul-Henning Kamp free(barlist, M_DEVBUF); 9536d9fcd03SWarner Losh return (EIO); 9546d9fcd03SWarner Losh } 95563fa9f4cSJonathan Chen start = rman_get_start(res); 95663fa9f4cSJonathan Chen end = rman_get_end(res); 95763fa9f4cSJonathan Chen DEVPRINTF((cbdev, "IO port at %x-%x\n", start, end)); 95863fa9f4cSJonathan Chen /* 95963fa9f4cSJonathan Chen * Now that we know the region is free, release it and hand it 96021677473SWarner Losh * out piece by piece. 96163fa9f4cSJonathan Chen */ 96263fa9f4cSJonathan Chen bus_release_resource(cbdev, SYS_RES_IOPORT, rid, res); 96363fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 96451715fe7SWarner Losh rle = barlist[tmp]; 96551715fe7SWarner Losh if (rle->type == SYS_RES_IOPORT) { 96651715fe7SWarner Losh cardbus_do_res(rle, child, start); 96751715fe7SWarner Losh start += rle->count; 96863fa9f4cSJonathan Chen } 96963fa9f4cSJonathan Chen } 97063fa9f4cSJonathan Chen } 97163fa9f4cSJonathan Chen 97263fa9f4cSJonathan Chen /* Allocate IRQ */ 97363fa9f4cSJonathan Chen rid = 0; 97463fa9f4cSJonathan Chen res = bus_alloc_resource(cbdev, SYS_RES_IRQ, &rid, 0, ~0UL, 1, 97563fa9f4cSJonathan Chen RF_SHAREABLE); 9766d9fcd03SWarner Losh if (res == NULL) { 9776d9fcd03SWarner Losh device_printf(cbdev, "Can't get memory for irq\n"); 978b44f8087SPoul-Henning Kamp free(barlist, M_DEVBUF); 9796d9fcd03SWarner Losh return (EIO); 9806d9fcd03SWarner Losh } 98151715fe7SWarner Losh start = rman_get_start(res); 98251715fe7SWarner Losh end = rman_get_end(res); 98351715fe7SWarner Losh bus_release_resource(cbdev, SYS_RES_IRQ, rid, res); 98451715fe7SWarner Losh resource_list_add(&dinfo->pci.resources, SYS_RES_IRQ, rid, start, end, 98551715fe7SWarner Losh 1); 98621677473SWarner Losh dinfo->pci.cfg.intline = rman_get_start(res); 98721677473SWarner Losh pci_write_config(child, PCIR_INTLINE, rman_get_start(res), 1); 98863fa9f4cSJonathan Chen 989214c0b3dSWarner Losh free(barlist, M_DEVBUF); 990a3133b58SWarner Losh return (0); 99163fa9f4cSJonathan Chen } 99263fa9f4cSJonathan Chen 99363fa9f4cSJonathan Chen /* 99463fa9f4cSJonathan Chen * Adding a memory/io resource (sans CIS) 99563fa9f4cSJonathan Chen */ 99663fa9f4cSJonathan Chen 99763fa9f4cSJonathan Chen static void 99863fa9f4cSJonathan Chen cardbus_add_map(device_t cbdev, device_t child, int reg) 99963fa9f4cSJonathan Chen { 100063fa9f4cSJonathan Chen struct cardbus_devinfo *dinfo = device_get_ivars(child); 100121677473SWarner Losh struct resource_list_entry *rle; 100266e390feSWarner Losh uint32_t size; 100366e390feSWarner Losh uint32_t testval; 100463fa9f4cSJonathan Chen int type; 100563fa9f4cSJonathan Chen 100621677473SWarner Losh SLIST_FOREACH(rle, &dinfo->pci.resources, link) { 100721677473SWarner Losh if (rle->rid == reg) 100863fa9f4cSJonathan Chen return; 100921677473SWarner Losh } 101063fa9f4cSJonathan Chen 101163fa9f4cSJonathan Chen if (reg == CARDBUS_ROM_REG) 101263fa9f4cSJonathan Chen testval = CARDBUS_ROM_ADDRMASK; 101363fa9f4cSJonathan Chen else 101463fa9f4cSJonathan Chen testval = ~0; 101563fa9f4cSJonathan Chen 101663fa9f4cSJonathan Chen pci_write_config(child, reg, testval, 4); 101763fa9f4cSJonathan Chen testval = pci_read_config(child, reg, 4); 101863fa9f4cSJonathan Chen 101963fa9f4cSJonathan Chen if (testval == ~0 || testval == 0) 102063fa9f4cSJonathan Chen return; 102163fa9f4cSJonathan Chen 102263fa9f4cSJonathan Chen if ((testval & 1) == 0) 102363fa9f4cSJonathan Chen type = SYS_RES_MEMORY; 102463fa9f4cSJonathan Chen else 102563fa9f4cSJonathan Chen type = SYS_RES_IOPORT; 102663fa9f4cSJonathan Chen 102763fa9f4cSJonathan Chen size = CARDBUS_MAPREG_MEM_SIZE(testval); 102821677473SWarner Losh device_printf(cbdev, "Resource not specified in CIS: id=%x, size=%x\n", 102921677473SWarner Losh reg, size); 103021677473SWarner Losh resource_list_add(&dinfo->pci.resources, type, reg, 0UL, ~0UL, size); 103163fa9f4cSJonathan Chen } 103263fa9f4cSJonathan Chen 103363fa9f4cSJonathan Chen static void 103463fa9f4cSJonathan Chen cardbus_pickup_maps(device_t cbdev, device_t child) 103563fa9f4cSJonathan Chen { 103663fa9f4cSJonathan Chen struct cardbus_devinfo *dinfo = device_get_ivars(child); 103763fa9f4cSJonathan Chen struct cardbus_quirk *q; 103863fa9f4cSJonathan Chen int reg; 103963fa9f4cSJonathan Chen 104063fa9f4cSJonathan Chen /* 104163fa9f4cSJonathan Chen * Try to pick up any resources that was not specified in CIS. 104263fa9f4cSJonathan Chen * Some devices (eg, 3c656) does not list all resources required by 104363fa9f4cSJonathan Chen * the driver in its CIS. 104463fa9f4cSJonathan Chen * XXX: should we do this or use quirks? 104563fa9f4cSJonathan Chen */ 10467ba175acSWarner Losh for (reg = 0; reg < dinfo->pci.cfg.nummaps; reg++) { 104763fa9f4cSJonathan Chen cardbus_add_map(cbdev, child, PCIR_MAPS + reg * 4); 104863fa9f4cSJonathan Chen } 104963fa9f4cSJonathan Chen 105063fa9f4cSJonathan Chen for (q = &cardbus_quirks[0]; q->devid; q++) { 105121677473SWarner Losh if (q->devid == ((dinfo->pci.cfg.device << 16) | dinfo->pci.cfg.vendor) 105263fa9f4cSJonathan Chen && q->type == CARDBUS_QUIRK_MAP_REG) { 105363fa9f4cSJonathan Chen cardbus_add_map(cbdev, child, q->arg1); 105463fa9f4cSJonathan Chen } 105563fa9f4cSJonathan Chen } 105663fa9f4cSJonathan Chen } 105763fa9f4cSJonathan Chen 10580c95c705SJonathan Chen int 105966e390feSWarner Losh cardbus_cis_read(device_t cbdev, device_t child, uint8_t id, 10600c95c705SJonathan Chen struct cis_tupleinfo **buff, int *nret) 10610c95c705SJonathan Chen { 10620c95c705SJonathan Chen struct tuple_callbacks cisread_callbacks[] = { 10630c95c705SJonathan Chen MAKETUPLE(NULL, nothing), 10640c95c705SJonathan Chen /* first entry will be overwritten */ 10650c95c705SJonathan Chen MAKETUPLE(NULL, nothing), 10660c95c705SJonathan Chen MAKETUPLE(DEVICE, nothing), 10670c95c705SJonathan Chen MAKETUPLE(LONG_LINK_CB, unhandled), 10680c95c705SJonathan Chen MAKETUPLE(INDIRECT, unhandled), 10690c95c705SJonathan Chen MAKETUPLE(CONFIG_CB, nothing), 10700c95c705SJonathan Chen MAKETUPLE(CFTABLE_ENTRY_CB, nothing), 10710c95c705SJonathan Chen MAKETUPLE(LONGLINK_MFC, unhandled), 10720c95c705SJonathan Chen MAKETUPLE(BAR, nothing), 10730c95c705SJonathan Chen MAKETUPLE(PWR_MGMNT, nothing), 10740c95c705SJonathan Chen MAKETUPLE(EXTDEVICE, nothing), 10750c95c705SJonathan Chen MAKETUPLE(CHECKSUM, nothing), 10760c95c705SJonathan Chen MAKETUPLE(LONGLINK_A, unhandled), 10770c95c705SJonathan Chen MAKETUPLE(LONGLINK_C, unhandled), 10780c95c705SJonathan Chen MAKETUPLE(LINKTARGET, nothing), 10790c95c705SJonathan Chen MAKETUPLE(NO_LINK, nothing), 10800c95c705SJonathan Chen MAKETUPLE(VERS_1, nothing), 10810c95c705SJonathan Chen MAKETUPLE(ALTSTR, nothing), 10820c95c705SJonathan Chen MAKETUPLE(DEVICE_A, nothing), 10830c95c705SJonathan Chen MAKETUPLE(JEDEC_C, nothing), 10840c95c705SJonathan Chen MAKETUPLE(JEDEC_A, nothing), 10850c95c705SJonathan Chen MAKETUPLE(CONFIG, nothing), 10860c95c705SJonathan Chen MAKETUPLE(CFTABLE_ENTRY, nothing), 10870c95c705SJonathan Chen MAKETUPLE(DEVICE_OC, nothing), 10880c95c705SJonathan Chen MAKETUPLE(DEVICE_OA, nothing), 10890c95c705SJonathan Chen MAKETUPLE(DEVICE_GEO, nothing), 10900c95c705SJonathan Chen MAKETUPLE(DEVICE_GEO_A, nothing), 10910c95c705SJonathan Chen MAKETUPLE(MANFID, nothing), 10920c95c705SJonathan Chen MAKETUPLE(FUNCID, nothing), 10930c95c705SJonathan Chen MAKETUPLE(FUNCE, nothing), 10940c95c705SJonathan Chen MAKETUPLE(SWIL, nothing), 10950c95c705SJonathan Chen MAKETUPLE(VERS_2, nothing), 10960c95c705SJonathan Chen MAKETUPLE(FORMAT, nothing), 10970c95c705SJonathan Chen MAKETUPLE(GEOMETRY, nothing), 10980c95c705SJonathan Chen MAKETUPLE(BYTEORDER, nothing), 10990c95c705SJonathan Chen MAKETUPLE(DATE, nothing), 11000c95c705SJonathan Chen MAKETUPLE(BATTERY, nothing), 11010c95c705SJonathan Chen MAKETUPLE(ORG, nothing), 11020c95c705SJonathan Chen MAKETUPLE(END, end), 11030c95c705SJonathan Chen MAKETUPLE(GENERIC, nothing), 11040c95c705SJonathan Chen }; 11050c95c705SJonathan Chen int ret; 11060c95c705SJonathan Chen 11070c95c705SJonathan Chen cisread_callbacks[0].id = id; 11080c95c705SJonathan Chen cisread_callbacks[0].name = "COPY"; 11090c95c705SJonathan Chen cisread_callbacks[0].func = decode_tuple_copy; 11100c95c705SJonathan Chen ncisread_buf = 0; 11110c95c705SJonathan Chen cisread_buf = NULL; 1112255b159fSJonathan Chen ret = cardbus_parse_cis(cbdev, child, cisread_callbacks); 11130c95c705SJonathan Chen 11140c95c705SJonathan Chen *buff = cisread_buf; 11150c95c705SJonathan Chen *nret = ncisread_buf; 1116a3133b58SWarner Losh return (ret); 11170c95c705SJonathan Chen } 11180c95c705SJonathan Chen 11190c95c705SJonathan Chen void 1120255b159fSJonathan Chen cardbus_cis_free(device_t cbdev, struct cis_tupleinfo *buff, int *nret) 11210c95c705SJonathan Chen { 11220c95c705SJonathan Chen int i; 11236f39832cSPeter Wemm for (i = 0; i < *nret; i++) 11240c95c705SJonathan Chen free(buff[i].data, M_DEVBUF); 11256f39832cSPeter Wemm if (*nret > 0) 11260c95c705SJonathan Chen free(buff, M_DEVBUF); 11270c95c705SJonathan Chen } 11280c95c705SJonathan Chen 11290c95c705SJonathan Chen int 1130255b159fSJonathan Chen cardbus_do_cis(device_t cbdev, device_t child) 11310c95c705SJonathan Chen { 113263fa9f4cSJonathan Chen int ret; 11330c95c705SJonathan Chen struct tuple_callbacks init_callbacks[] = { 11340c95c705SJonathan Chen MAKETUPLE(NULL, generic), 11350c95c705SJonathan Chen MAKETUPLE(DEVICE, generic), 11360c95c705SJonathan Chen MAKETUPLE(LONG_LINK_CB, unhandled), 11370c95c705SJonathan Chen MAKETUPLE(INDIRECT, unhandled), 11380c95c705SJonathan Chen MAKETUPLE(CONFIG_CB, generic), 11390c95c705SJonathan Chen MAKETUPLE(CFTABLE_ENTRY_CB, generic), 11400c95c705SJonathan Chen MAKETUPLE(LONGLINK_MFC, unhandled), 11410c95c705SJonathan Chen MAKETUPLE(BAR, bar), 11420c95c705SJonathan Chen MAKETUPLE(PWR_MGMNT, generic), 11430c95c705SJonathan Chen MAKETUPLE(EXTDEVICE, generic), 11440c95c705SJonathan Chen MAKETUPLE(CHECKSUM, generic), 11450c95c705SJonathan Chen MAKETUPLE(LONGLINK_A, unhandled), 11460c95c705SJonathan Chen MAKETUPLE(LONGLINK_C, unhandled), 11470c95c705SJonathan Chen MAKETUPLE(LINKTARGET, linktarget), 11480c95c705SJonathan Chen MAKETUPLE(NO_LINK, generic), 11490c95c705SJonathan Chen MAKETUPLE(VERS_1, vers_1), 11500c95c705SJonathan Chen MAKETUPLE(ALTSTR, generic), 11510c95c705SJonathan Chen MAKETUPLE(DEVICE_A, generic), 11520c95c705SJonathan Chen MAKETUPLE(JEDEC_C, generic), 11530c95c705SJonathan Chen MAKETUPLE(JEDEC_A, generic), 11540c95c705SJonathan Chen MAKETUPLE(CONFIG, generic), 11550c95c705SJonathan Chen MAKETUPLE(CFTABLE_ENTRY, generic), 11560c95c705SJonathan Chen MAKETUPLE(DEVICE_OC, generic), 11570c95c705SJonathan Chen MAKETUPLE(DEVICE_OA, generic), 11580c95c705SJonathan Chen MAKETUPLE(DEVICE_GEO, generic), 11590c95c705SJonathan Chen MAKETUPLE(DEVICE_GEO_A, generic), 11600c95c705SJonathan Chen MAKETUPLE(MANFID, manfid), 11610c95c705SJonathan Chen MAKETUPLE(FUNCID, funcid), 11620c95c705SJonathan Chen MAKETUPLE(FUNCE, funce), 11630c95c705SJonathan Chen MAKETUPLE(SWIL, generic), 11640c95c705SJonathan Chen MAKETUPLE(VERS_2, generic), 11650c95c705SJonathan Chen MAKETUPLE(FORMAT, generic), 11660c95c705SJonathan Chen MAKETUPLE(GEOMETRY, generic), 11670c95c705SJonathan Chen MAKETUPLE(BYTEORDER, generic), 11680c95c705SJonathan Chen MAKETUPLE(DATE, generic), 11690c95c705SJonathan Chen MAKETUPLE(BATTERY, generic), 11700c95c705SJonathan Chen MAKETUPLE(ORG, generic), 11710c95c705SJonathan Chen MAKETUPLE(END, end), 11720c95c705SJonathan Chen MAKETUPLE(GENERIC, generic), 11730c95c705SJonathan Chen }; 117463fa9f4cSJonathan Chen 117563fa9f4cSJonathan Chen ret = cardbus_parse_cis(cbdev, child, init_callbacks); 117663fa9f4cSJonathan Chen if (ret < 0) 1177a3133b58SWarner Losh return (ret); 117863fa9f4cSJonathan Chen cardbus_pickup_maps(cbdev, child); 1179a3133b58SWarner Losh return (cardbus_alloc_resources(cbdev, child)); 11800c95c705SJonathan Chen } 1181