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 #define CARDBUS_DEBUG 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> 460db7e66cSJonathan Chen 4763fa9f4cSJonathan Chen #include <dev/pci/pcivar.h> 4863fa9f4cSJonathan Chen #include <dev/pci/pcireg.h> 4963fa9f4cSJonathan Chen #include <sys/pciio.h> 500db7e66cSJonathan Chen 510db7e66cSJonathan Chen #include <dev/cardbus/cardbusreg.h> 5263fa9f4cSJonathan Chen #include <dev/cardbus/cardbusvar.h> 530db7e66cSJonathan Chen #include <dev/cardbus/cardbus_cis.h> 540db7e66cSJonathan Chen 550c95c705SJonathan Chen #include "card_if.h" 560c95c705SJonathan Chen 570db7e66cSJonathan Chen #if defined CARDBUS_DEBUG 580db7e66cSJonathan Chen #define DPRINTF(a) printf a 590db7e66cSJonathan Chen #define DEVPRINTF(x) device_printf x 600db7e66cSJonathan Chen #else 610db7e66cSJonathan Chen #define DPRINTF(a) 620db7e66cSJonathan Chen #define DEVPRINTF(x) 630db7e66cSJonathan Chen #endif 640db7e66cSJonathan Chen 650db7e66cSJonathan Chen #if !defined(lint) 660db7e66cSJonathan Chen static const char rcsid[] = 670db7e66cSJonathan Chen "$FreeBSD$"; 680db7e66cSJonathan Chen #endif 690db7e66cSJonathan Chen 700c95c705SJonathan Chen #define DECODE_PARAMS \ 71255b159fSJonathan Chen (device_t cbdev, device_t child, int id, int len, \ 7263fa9f4cSJonathan Chen u_int8_t *tupledata, u_int32_t start, u_int32_t *off, \ 730c95c705SJonathan Chen struct tuple_callbacks *info) 740db7e66cSJonathan Chen 750c95c705SJonathan Chen struct tuple_callbacks { 760c95c705SJonathan Chen int id; 770db7e66cSJonathan Chen char *name; 780c95c705SJonathan Chen int (*func) DECODE_PARAMS; 790db7e66cSJonathan Chen }; 80255b159fSJonathan Chen 81255b159fSJonathan Chen #define DECODE_PROTOTYPE(NAME) static int decode_tuple_ ## NAME DECODE_PARAMS 82255b159fSJonathan Chen DECODE_PROTOTYPE(generic); 83255b159fSJonathan Chen DECODE_PROTOTYPE(nothing); 84255b159fSJonathan Chen DECODE_PROTOTYPE(copy); 85255b159fSJonathan Chen DECODE_PROTOTYPE(linktarget); 86255b159fSJonathan Chen DECODE_PROTOTYPE(vers_1); 87255b159fSJonathan Chen DECODE_PROTOTYPE(funcid); 88255b159fSJonathan Chen DECODE_PROTOTYPE(manfid); 89255b159fSJonathan Chen DECODE_PROTOTYPE(funce); 90255b159fSJonathan Chen DECODE_PROTOTYPE(bar); 91255b159fSJonathan Chen DECODE_PROTOTYPE(unhandled); 92255b159fSJonathan Chen DECODE_PROTOTYPE(end); 93255b159fSJonathan Chen static int cardbus_read_tuple_conf(device_t cbdev, device_t child, 9463fa9f4cSJonathan Chen u_int32_t start, u_int32_t *off, int *tupleid, int *len, 95255b159fSJonathan Chen u_int8_t *tupledata); 9663fa9f4cSJonathan Chen static int cardbus_read_tuple_mem(device_t cbdev, struct resource *res, 9763fa9f4cSJonathan Chen u_int32_t start, u_int32_t *off, int *tupleid, int *len, 98255b159fSJonathan Chen u_int8_t *tupledata); 99255b159fSJonathan Chen static int cardbus_read_tuple(device_t cbdev, device_t child, 10063fa9f4cSJonathan Chen struct resource *res, u_int32_t start, u_int32_t *off, 10163fa9f4cSJonathan Chen int *tupleid, int *len, u_int8_t *tupledata); 10263fa9f4cSJonathan Chen static void cardbus_read_tuple_finish(device_t cbdev, device_t child, 10363fa9f4cSJonathan Chen int rid, struct resource *res); 10463fa9f4cSJonathan Chen static struct resource *cardbus_read_tuple_init(device_t cbdev, device_t child, 10563fa9f4cSJonathan Chen u_int32_t *start, int *rid); 106255b159fSJonathan Chen static int decode_tuple(device_t cbdev, device_t child, int tupleid, 10763fa9f4cSJonathan Chen int len, u_int8_t *tupledata, u_int32_t start, 108255b159fSJonathan Chen u_int32_t *off, struct tuple_callbacks *callbacks); 109255b159fSJonathan Chen static int cardbus_parse_cis(device_t cbdev, device_t child, 110255b159fSJonathan Chen struct tuple_callbacks *callbacks); 11163fa9f4cSJonathan Chen static int barsort(const void *a, const void *b); 11263fa9f4cSJonathan Chen static int cardbus_alloc_resources(device_t cbdev, device_t child); 11363fa9f4cSJonathan Chen static void cardbus_add_map(device_t cbdev, device_t child, int reg); 11463fa9f4cSJonathan Chen static void cardbus_pickup_maps(device_t cbdev, device_t child); 11563fa9f4cSJonathan Chen 116255b159fSJonathan Chen 1170c95c705SJonathan Chen #define MAKETUPLE(NAME,FUNC) { CISTPL_ ## NAME, #NAME, decode_tuple_ ## FUNC } 1180db7e66cSJonathan Chen 1190db7e66cSJonathan Chen static char *funcnames[] = { 1200db7e66cSJonathan Chen "Multi-Functioned", 1210db7e66cSJonathan Chen "Memory", 1220db7e66cSJonathan Chen "Serial Port", 1230db7e66cSJonathan Chen "Parallel Port", 1240db7e66cSJonathan Chen "Fixed Disk", 1250db7e66cSJonathan Chen "Video Adaptor", 1260db7e66cSJonathan Chen "Network Adaptor", 1270db7e66cSJonathan Chen "AIMS", 1280db7e66cSJonathan Chen "SCSI", 1290db7e66cSJonathan Chen "Security" 1300db7e66cSJonathan Chen }; 1310db7e66cSJonathan Chen 13263fa9f4cSJonathan Chen struct cardbus_quirk { 13363fa9f4cSJonathan Chen u_int32_t devid; /* Vendor/device of the card */ 13463fa9f4cSJonathan Chen int type; 13563fa9f4cSJonathan Chen #define CARDBUS_QUIRK_MAP_REG 1 /* PCI map register in weird place */ 13663fa9f4cSJonathan Chen int arg1; 13763fa9f4cSJonathan Chen int arg2; 13863fa9f4cSJonathan Chen }; 13963fa9f4cSJonathan Chen 14063fa9f4cSJonathan Chen struct cardbus_quirk cardbus_quirks[] = { 14163fa9f4cSJonathan Chen { 0 } 14263fa9f4cSJonathan Chen }; 14363fa9f4cSJonathan Chen 1440c95c705SJonathan Chen static struct cis_tupleinfo *cisread_buf; 1450c95c705SJonathan Chen static int ncisread_buf; 1460c95c705SJonathan Chen 147255b159fSJonathan Chen /* 148255b159fSJonathan Chen * Handler functions for various CIS tuples 149255b159fSJonathan Chen */ 150255b159fSJonathan Chen 1510db7e66cSJonathan Chen DECODE_PROTOTYPE(generic) 1520db7e66cSJonathan Chen { 1530db7e66cSJonathan Chen #ifdef CARDBUS_DEBUG 1540db7e66cSJonathan Chen int i; 1550db7e66cSJonathan Chen 1560db7e66cSJonathan Chen if (info) 1570db7e66cSJonathan Chen printf("TUPLE: %s [%d]:", info->name, len); 1580db7e66cSJonathan Chen else 1590db7e66cSJonathan Chen printf("TUPLE: Unknown(0x%02x) [%d]:", id, len); 1600db7e66cSJonathan Chen 1610db7e66cSJonathan Chen for (i = 0; i < len; i++) { 1620db7e66cSJonathan Chen if (i % 0x10 == 0 && len > 0x10) 1630db7e66cSJonathan Chen printf("\n 0x%02x:", i); 1647bec1dd5SJonathan Chen printf(" %02x", tupledata[i]); 1650db7e66cSJonathan Chen } 1660db7e66cSJonathan Chen printf("\n"); 1670db7e66cSJonathan Chen #endif 1680db7e66cSJonathan Chen return 0; 1690db7e66cSJonathan Chen } 1700db7e66cSJonathan Chen 1710c95c705SJonathan Chen DECODE_PROTOTYPE(nothing) 1720c95c705SJonathan Chen { 1730c95c705SJonathan Chen return 0; 1740c95c705SJonathan Chen } 1750c95c705SJonathan Chen 1760c95c705SJonathan Chen DECODE_PROTOTYPE(copy) 1770c95c705SJonathan Chen { 1780c95c705SJonathan Chen struct cis_tupleinfo *tmpbuf; 1790c95c705SJonathan Chen 1800c95c705SJonathan Chen tmpbuf = malloc(sizeof(struct cis_tupleinfo) * (ncisread_buf+1), 1810c95c705SJonathan Chen M_DEVBUF, M_WAITOK); 1820c95c705SJonathan Chen if (ncisread_buf > 0) { 1830c95c705SJonathan Chen memcpy(tmpbuf, cisread_buf, 1840c95c705SJonathan Chen sizeof(struct cis_tupleinfo) * ncisread_buf); 1850c95c705SJonathan Chen free(cisread_buf, M_DEVBUF); 1860c95c705SJonathan Chen } 1870c95c705SJonathan Chen cisread_buf = tmpbuf; 1880c95c705SJonathan Chen 1890c95c705SJonathan Chen cisread_buf[ncisread_buf].id = id; 1900c95c705SJonathan Chen cisread_buf[ncisread_buf].len = len; 1910c95c705SJonathan Chen cisread_buf[ncisread_buf].data = malloc(len, M_DEVBUF, M_WAITOK); 1920c95c705SJonathan Chen memcpy(cisread_buf[ncisread_buf].data, tupledata, len); 1930c95c705SJonathan Chen ncisread_buf++; 1940c95c705SJonathan Chen return 0; 1950c95c705SJonathan Chen } 1960c95c705SJonathan Chen 1970db7e66cSJonathan Chen DECODE_PROTOTYPE(linktarget) 1980db7e66cSJonathan Chen { 19949f158ccSJonathan Chen #ifdef CARDBUS_DEBUG 20049f158ccSJonathan Chen int i; 20149f158ccSJonathan Chen 20249f158ccSJonathan Chen printf("TUPLE: %s [%d]:", info->name, len); 20349f158ccSJonathan Chen 20449f158ccSJonathan Chen for (i = 0; i < len; i++) { 20549f158ccSJonathan Chen if (i % 0x10 == 0 && len > 0x10) 20649f158ccSJonathan Chen printf("\n 0x%02x:", i); 20749f158ccSJonathan Chen printf(" %02x", tupledata[i]); 20849f158ccSJonathan Chen } 20949f158ccSJonathan Chen printf("\n"); 21049f158ccSJonathan Chen #endif 2117bec1dd5SJonathan Chen if (len != 3 || tupledata[0] != 'C' || tupledata[1] != 'I' || 2127bec1dd5SJonathan Chen tupledata[2] != 'S') { 2130db7e66cSJonathan Chen printf("Invalid data for CIS Link Target!\n"); 214255b159fSJonathan Chen decode_tuple_generic(cbdev, child, id, len, tupledata, 21549f158ccSJonathan Chen start, off, info); 2160db7e66cSJonathan Chen return EINVAL; 2170db7e66cSJonathan Chen } 2180db7e66cSJonathan Chen return 0; 2190db7e66cSJonathan Chen } 2200db7e66cSJonathan Chen 2210db7e66cSJonathan Chen DECODE_PROTOTYPE(vers_1) 2220db7e66cSJonathan Chen { 2230db7e66cSJonathan Chen int i; 2247bec1dd5SJonathan Chen printf("Product version: %d.%d\n", tupledata[0], tupledata[1]); 2250db7e66cSJonathan Chen printf("Product name: "); 2260db7e66cSJonathan Chen for (i = 2; i < len; i++) { 2277bec1dd5SJonathan Chen if (tupledata[i] == '\0') 2280db7e66cSJonathan Chen printf(" | "); 2297bec1dd5SJonathan Chen else if (tupledata[i] == 0xff) 2300db7e66cSJonathan Chen break; 2310db7e66cSJonathan Chen else 2327bec1dd5SJonathan Chen printf("%c", tupledata[i]); 2330db7e66cSJonathan Chen } 2340db7e66cSJonathan Chen printf("\n"); 2350db7e66cSJonathan Chen return 0; 2360db7e66cSJonathan Chen } 2370db7e66cSJonathan Chen 2380db7e66cSJonathan Chen DECODE_PROTOTYPE(funcid) 2390db7e66cSJonathan Chen { 2400db7e66cSJonathan Chen int i; 2410db7e66cSJonathan Chen int numnames = sizeof(funcnames) / sizeof(funcnames[0]); 2420db7e66cSJonathan Chen 2430db7e66cSJonathan Chen printf("Functions: "); 2440db7e66cSJonathan Chen for (i = 0; i < len; i++) { 2457bec1dd5SJonathan Chen if (tupledata[i] < numnames) 2467bec1dd5SJonathan Chen printf("%s", funcnames[tupledata[i]]); 2470db7e66cSJonathan Chen else 2487bec1dd5SJonathan Chen printf("Unknown(%d)", tupledata[i]); 249255b159fSJonathan Chen if (i < len-1) 250255b159fSJonathan Chen printf(", "); 2510db7e66cSJonathan Chen } 2520db7e66cSJonathan Chen printf("\n"); 2530db7e66cSJonathan Chen return 0; 2540db7e66cSJonathan Chen } 2550db7e66cSJonathan Chen 2560db7e66cSJonathan Chen DECODE_PROTOTYPE(manfid) 2570db7e66cSJonathan Chen { 2580db7e66cSJonathan Chen int i; 2590db7e66cSJonathan Chen printf("Manufacturer ID: "); 2600db7e66cSJonathan Chen for (i = 0; i < len; i++) 2617bec1dd5SJonathan Chen printf("%02x", tupledata[i]); 2620db7e66cSJonathan Chen printf("\n"); 2630db7e66cSJonathan Chen return 0; 2640db7e66cSJonathan Chen } 2650db7e66cSJonathan Chen 2660db7e66cSJonathan Chen DECODE_PROTOTYPE(funce) 2670db7e66cSJonathan Chen { 2680db7e66cSJonathan Chen int i; 2690db7e66cSJonathan Chen printf("Function Extension: "); 2700db7e66cSJonathan Chen for (i = 0; i < len; i++) 2717bec1dd5SJonathan Chen printf("%02x", tupledata[i]); 2720db7e66cSJonathan Chen printf("\n"); 2730db7e66cSJonathan Chen return 0; 2740db7e66cSJonathan Chen } 2750db7e66cSJonathan Chen 2760db7e66cSJonathan Chen DECODE_PROTOTYPE(bar) 2770db7e66cSJonathan Chen { 2780db7e66cSJonathan Chen if (len != 6) { 2790db7e66cSJonathan Chen printf("*** ERROR *** BAR length not 6 (%d)\n", len); 2800db7e66cSJonathan Chen return EINVAL; 2810db7e66cSJonathan Chen } else { 28263fa9f4cSJonathan Chen struct cardbus_devinfo *dinfo = device_get_ivars(child); 2830db7e66cSJonathan Chen int type; 2840db7e66cSJonathan Chen int reg; 2850db7e66cSJonathan Chen u_int32_t bar; 2860db7e66cSJonathan Chen 2877bec1dd5SJonathan Chen reg = *(u_int16_t*)tupledata; 2887bec1dd5SJonathan Chen len = *(u_int32_t*)(tupledata + 2); 2890db7e66cSJonathan Chen if (reg & TPL_BAR_REG_AS) { 2900db7e66cSJonathan Chen type = SYS_RES_IOPORT; 2910db7e66cSJonathan Chen } else { 2920db7e66cSJonathan Chen type = SYS_RES_MEMORY; 2930db7e66cSJonathan Chen } 2940db7e66cSJonathan Chen bar = (reg & TPL_BAR_REG_ASI_MASK) - 1; 295255b159fSJonathan Chen if (bar < 0 || bar > 5 || 296255b159fSJonathan Chen (type == SYS_RES_IOPORT && bar == 5)) { 297255b159fSJonathan Chen device_printf(cbdev, "Invalid BAR number: %02x(%02x)\n", 2980db7e66cSJonathan Chen reg, bar); 2990c95c705SJonathan Chen return 0; 3000db7e66cSJonathan Chen } 3010db7e66cSJonathan Chen bar = CARDBUS_BASE0_REG + bar * 4; 30263fa9f4cSJonathan Chen if (type == SYS_RES_MEMORY) { 30363fa9f4cSJonathan Chen if (bar & TPL_BAR_REG_PREFETCHABLE) 30463fa9f4cSJonathan Chen dinfo->mprefetchable |= BARBIT(bar); 30563fa9f4cSJonathan Chen if (bar & TPL_BAR_REG_BELOW1MB) 30663fa9f4cSJonathan Chen dinfo->mbelow1mb |= BARBIT(bar); 30763fa9f4cSJonathan Chen } else if (type == SYS_RES_IOPORT) { 30863fa9f4cSJonathan Chen if (bar & TPL_BAR_REG_BELOW1MB) 30963fa9f4cSJonathan Chen dinfo->ibelow1mb |= BARBIT(bar); 3100db7e66cSJonathan Chen } 31163fa9f4cSJonathan Chen DEVPRINTF((cbdev, "Opening BAR: type=%s, bar=%02x, " 31263fa9f4cSJonathan Chen "len=%04x%s%s\n", 31363fa9f4cSJonathan Chen (type==SYS_RES_MEMORY)?"MEM":"IO", bar, len, 31463fa9f4cSJonathan Chen (type==SYS_RES_MEMORY&&dinfo->mprefetchable&BARBIT(bar))? 31563fa9f4cSJonathan Chen " (Prefetchable)":"", 31663fa9f4cSJonathan Chen type==SYS_RES_MEMORY? 31763fa9f4cSJonathan Chen ((dinfo->mbelow1mb&BARBIT(bar))?" (Below 1Mb)":"") 31863fa9f4cSJonathan Chen :(dinfo->ibelow1mb&BARBIT(bar))?" (Below 1Mb)":"" 31963fa9f4cSJonathan Chen )); 32063fa9f4cSJonathan Chen 32163fa9f4cSJonathan Chen resource_list_add(&dinfo->resources, type, bar, 0UL, ~0UL, len); 3220db7e66cSJonathan Chen } 3230db7e66cSJonathan Chen return 0; 3240db7e66cSJonathan Chen } 3250db7e66cSJonathan Chen 3260db7e66cSJonathan Chen DECODE_PROTOTYPE(unhandled) 3270db7e66cSJonathan Chen { 3280db7e66cSJonathan Chen printf("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len); 3290db7e66cSJonathan Chen return -1; 3300db7e66cSJonathan Chen } 3310db7e66cSJonathan Chen 3320db7e66cSJonathan Chen DECODE_PROTOTYPE(end) 3330db7e66cSJonathan Chen { 3340c95c705SJonathan Chen printf("CIS reading done\n"); 3357bec1dd5SJonathan Chen return 0; 3360db7e66cSJonathan Chen } 3370db7e66cSJonathan Chen 338255b159fSJonathan Chen /* 339255b159fSJonathan Chen * Functions to read the a tuple from the card 340255b159fSJonathan Chen */ 341255b159fSJonathan Chen 3420db7e66cSJonathan Chen static int 34363fa9f4cSJonathan Chen cardbus_read_tuple_conf(device_t cbdev, device_t child, u_int32_t start, 344255b159fSJonathan Chen u_int32_t *off, int *tupleid, int *len, u_int8_t *tupledata) 3457bec1dd5SJonathan Chen { 3467bec1dd5SJonathan Chen int i, j; 3477bec1dd5SJonathan Chen u_int32_t e; 34849f158ccSJonathan Chen u_int32_t loc; 3497bec1dd5SJonathan Chen 35063fa9f4cSJonathan Chen loc = start + *off; 35149f158ccSJonathan Chen 35249f158ccSJonathan Chen e = pci_read_config(child, loc - loc % 4, 4); 35349f158ccSJonathan Chen for (j = loc % 4; j > 0; j--) 3547bec1dd5SJonathan Chen e >>= 8; 3557bec1dd5SJonathan Chen *len = 0; 35649f158ccSJonathan Chen for (i = loc, j = -2; j < *len; j++, i++) { 3577bec1dd5SJonathan Chen if (i % 4 == 0) 3587bec1dd5SJonathan Chen e = pci_read_config(child, i, 4); 3597bec1dd5SJonathan Chen if (j == -2) 3607bec1dd5SJonathan Chen *tupleid = 0xff & e; 3617bec1dd5SJonathan Chen else if (j == -1) 3627bec1dd5SJonathan Chen *len = 0xff & e; 3637bec1dd5SJonathan Chen else 3647bec1dd5SJonathan Chen tupledata[j] = 0xff & e; 3657bec1dd5SJonathan Chen e >>= 8; 3667bec1dd5SJonathan Chen } 3677bec1dd5SJonathan Chen *off += *len + 2; 3687bec1dd5SJonathan Chen return 0; 3697bec1dd5SJonathan Chen } 3707bec1dd5SJonathan Chen 3717bec1dd5SJonathan Chen static int 37263fa9f4cSJonathan Chen cardbus_read_tuple_mem(device_t cbdev, struct resource *res, u_int32_t start, 373255b159fSJonathan Chen u_int32_t *off, int *tupleid, int *len, u_int8_t *tupledata) 3740db7e66cSJonathan Chen { 37563fa9f4cSJonathan Chen bus_space_tag_t bt; 37663fa9f4cSJonathan Chen bus_space_handle_t bh; 37763fa9f4cSJonathan Chen int ret; 3780db7e66cSJonathan Chen 37963fa9f4cSJonathan Chen bt = rman_get_bustag(res); 38063fa9f4cSJonathan Chen bh = rman_get_bushandle(res); 3810db7e66cSJonathan Chen 38263fa9f4cSJonathan Chen *tupleid = bus_space_read_1(bt, bh, start + *off); 38363fa9f4cSJonathan Chen *len = bus_space_read_1(bt, bh, start + *off + 1); 38463fa9f4cSJonathan Chen bus_space_read_region_1(bt, bh, *off + start + 2, tupledata, *len); 38563fa9f4cSJonathan Chen ret = 0; 38663fa9f4cSJonathan Chen *off += *len + 2; 38763fa9f4cSJonathan Chen return ret; 3880db7e66cSJonathan Chen } 38963fa9f4cSJonathan Chen 39063fa9f4cSJonathan Chen static int 39163fa9f4cSJonathan Chen cardbus_read_tuple(device_t cbdev, device_t child, struct resource *res, 39263fa9f4cSJonathan Chen u_int32_t start, u_int32_t *off, int *tupleid, int *len, 39363fa9f4cSJonathan Chen u_int8_t *tupledata) 39463fa9f4cSJonathan Chen { 39563fa9f4cSJonathan Chen if (res == (struct resource*)~0UL) { 39663fa9f4cSJonathan Chen return cardbus_read_tuple_conf(cbdev, child, start, off, 39763fa9f4cSJonathan Chen tupleid, len, tupledata); 39863fa9f4cSJonathan Chen } else { 39963fa9f4cSJonathan Chen return cardbus_read_tuple_mem(cbdev, res, start, off, 40063fa9f4cSJonathan Chen tupleid, len, tupledata); 40163fa9f4cSJonathan Chen } 40263fa9f4cSJonathan Chen } 40363fa9f4cSJonathan Chen 40463fa9f4cSJonathan Chen static void 40563fa9f4cSJonathan Chen cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid, 40663fa9f4cSJonathan Chen struct resource *res) 40763fa9f4cSJonathan Chen { 40863fa9f4cSJonathan Chen if (res != (struct resource*)~0UL) { 40963fa9f4cSJonathan Chen bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res); 41063fa9f4cSJonathan Chen pci_write_config(child, rid, 0, 4); 41163fa9f4cSJonathan Chen PCI_DISABLE_IO(cbdev, child, SYS_RES_MEMORY); 41263fa9f4cSJonathan Chen } 41363fa9f4cSJonathan Chen } 41463fa9f4cSJonathan Chen 41563fa9f4cSJonathan Chen static struct resource * 41663fa9f4cSJonathan Chen cardbus_read_tuple_init(device_t cbdev, device_t child, u_int32_t *start, 41763fa9f4cSJonathan Chen int *rid) 41863fa9f4cSJonathan Chen { 41963fa9f4cSJonathan Chen u_int32_t testval; 42063fa9f4cSJonathan Chen u_int32_t size; 42163fa9f4cSJonathan Chen struct resource *res; 42263fa9f4cSJonathan Chen 42363fa9f4cSJonathan Chen switch (CARDBUS_CIS_SPACE(*start)) { 42463fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_TUPLE: 42563fa9f4cSJonathan Chen /* CIS in tuple space need no initialization */ 42663fa9f4cSJonathan Chen return (struct resource*)~0UL; 42763fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR0: 42863fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR1: 42963fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR2: 43063fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR3: 43163fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR4: 43263fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_BAR5: 43363fa9f4cSJonathan Chen *rid = CARDBUS_BASE0_REG + (CARDBUS_CIS_SPACE(*start) - 1) * 4; 43463fa9f4cSJonathan Chen pci_write_config(child, *rid, ~0UL, 4); 43563fa9f4cSJonathan Chen break; 43663fa9f4cSJonathan Chen case CARDBUS_CIS_ASI_ROM: 43763fa9f4cSJonathan Chen *rid = CARDBUS_ROM_REG; 43863fa9f4cSJonathan Chen pci_write_config(child, *rid, CARDBUS_ROM_ADDRMASK, 4); 43963fa9f4cSJonathan Chen break; 44063fa9f4cSJonathan Chen default: 44163fa9f4cSJonathan Chen device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n", 44263fa9f4cSJonathan Chen CARDBUS_CIS_SPACE(*start)); 44363fa9f4cSJonathan Chen return NULL; 44463fa9f4cSJonathan Chen } 44563fa9f4cSJonathan Chen 44663fa9f4cSJonathan Chen /* figure out how much space we need */ 44763fa9f4cSJonathan Chen testval = pci_read_config(child, *rid, 4); 44863fa9f4cSJonathan Chen if (testval & 1) { 44963fa9f4cSJonathan Chen device_printf(cbdev, "CIS Space is IO, expecting memory.\n"); 45063fa9f4cSJonathan Chen return NULL; 45163fa9f4cSJonathan Chen } 45263fa9f4cSJonathan Chen size = CARDBUS_MAPREG_MEM_SIZE(testval); 45363fa9f4cSJonathan Chen if (size < 4096) 45463fa9f4cSJonathan Chen size = 4096; 45563fa9f4cSJonathan Chen /* allocate the memory space to read CIS */ 45663fa9f4cSJonathan Chen res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, rid, 0, ~0, size, 45763fa9f4cSJonathan Chen rman_make_alignment_flags(size) | RF_ACTIVE); 45863fa9f4cSJonathan Chen if (res == NULL) { 45963fa9f4cSJonathan Chen device_printf(cbdev, "Unable to allocate resource " 46063fa9f4cSJonathan Chen "to read CIS.\n"); 46163fa9f4cSJonathan Chen return NULL; 46263fa9f4cSJonathan Chen } 46363fa9f4cSJonathan Chen pci_write_config(child, *rid, 46463fa9f4cSJonathan Chen rman_get_start(res) | ((*rid == CARDBUS_ROM_REG)? 46563fa9f4cSJonathan Chen CARDBUS_ROM_ENABLE : 0), 46663fa9f4cSJonathan Chen 4); 46763fa9f4cSJonathan Chen PCI_ENABLE_IO(cbdev, child, SYS_RES_MEMORY); 46863fa9f4cSJonathan Chen 46963fa9f4cSJonathan Chen /* Flip to the right ROM image if CIS is in ROM */ 47063fa9f4cSJonathan Chen if (CARDBUS_CIS_SPACE(*start) == CARDBUS_CIS_ASI_ROM) { 47163fa9f4cSJonathan Chen bus_space_tag_t bt; 47263fa9f4cSJonathan Chen bus_space_handle_t bh; 47363fa9f4cSJonathan Chen int imagenum; 47463fa9f4cSJonathan Chen u_int32_t imagesize; 47563fa9f4cSJonathan Chen int mystart = 0; 47663fa9f4cSJonathan Chen int romnum = 0; 47763fa9f4cSJonathan Chen int dataptr; 47863fa9f4cSJonathan Chen 47963fa9f4cSJonathan Chen bt = rman_get_bustag(res); 48063fa9f4cSJonathan Chen bh = rman_get_bushandle(res); 48163fa9f4cSJonathan Chen 48263fa9f4cSJonathan Chen imagenum = CARDBUS_CIS_ASI_ROM_IMAGE(*start); 48363fa9f4cSJonathan Chen for (romnum = 0;; romnum++) { 48463fa9f4cSJonathan Chen if (bus_space_read_2(bt, bh, 48563fa9f4cSJonathan Chen mystart+CARDBUS_EXROM_SIGNATURE) != 0xaa55) { 48663fa9f4cSJonathan Chen device_printf(cbdev, "Bad header in rom %d: " 48763fa9f4cSJonathan Chen "[%x] %04x\n", romnum, mystart + 48863fa9f4cSJonathan Chen CARDBUS_EXROM_SIGNATURE, 48963fa9f4cSJonathan Chen bus_space_read_2(bt, bh, 49063fa9f4cSJonathan Chen mystart+CARDBUS_EXROM_SIGNATURE)); 49163fa9f4cSJonathan Chen bus_release_resource(cbdev, SYS_RES_MEMORY, 49263fa9f4cSJonathan Chen *rid, res); 49363fa9f4cSJonathan Chen *rid = 0; 49463fa9f4cSJonathan Chen return NULL; 49563fa9f4cSJonathan Chen } 49663fa9f4cSJonathan Chen dataptr = mystart + bus_space_read_2(bt, bh, 49763fa9f4cSJonathan Chen mystart + CARDBUS_EXROM_DATA_PTR); 49863fa9f4cSJonathan Chen imagesize = bus_space_read_2(bt, bh, 49963fa9f4cSJonathan Chen dataptr + CARDBUS_EXROM_DATA_IMAGE_LENGTH); 5000db7e66cSJonathan Chen 5017bec1dd5SJonathan Chen if (imagesize == 0) { 5020db7e66cSJonathan Chen /* 5030db7e66cSJonathan Chen * XXX some ROMs seem to have this as zero, 5040db7e66cSJonathan Chen * can we assume this means 1 block? 5050db7e66cSJonathan Chen */ 5060db7e66cSJonathan Chen imagesize = 1; 5077bec1dd5SJonathan Chen } 5080db7e66cSJonathan Chen imagesize <<= 9; 5090db7e66cSJonathan Chen 51063fa9f4cSJonathan Chen if (romnum == imagenum) 51163fa9f4cSJonathan Chen break; 51263fa9f4cSJonathan Chen if ((bus_space_read_1(bt, bh, mystart + 51363fa9f4cSJonathan Chen CARDBUS_EXROM_DATA_INDICATOR) & 0x80) == 0) { 51463fa9f4cSJonathan Chen device_printf(cbdev, "Cannot read CIS: " 51563fa9f4cSJonathan Chen "Not enough images of rom\n"); 51663fa9f4cSJonathan Chen return NULL; 5170db7e66cSJonathan Chen } 51863fa9f4cSJonathan Chen mystart += imagesize; 5190db7e66cSJonathan Chen } 52063fa9f4cSJonathan Chen *start = mystart + CARDBUS_CIS_ADDR(*start); 5210db7e66cSJonathan Chen } else { 52263fa9f4cSJonathan Chen *start = CARDBUS_CIS_SPACE(*start); 5230db7e66cSJonathan Chen } 52463fa9f4cSJonathan Chen return res; 5257bec1dd5SJonathan Chen } 5267bec1dd5SJonathan Chen 527255b159fSJonathan Chen /* 528255b159fSJonathan Chen * Dispatch the right handler function per tuple 529255b159fSJonathan Chen */ 530255b159fSJonathan Chen 5317bec1dd5SJonathan Chen static int 532255b159fSJonathan Chen decode_tuple(device_t cbdev, device_t child, int tupleid, int len, 53363fa9f4cSJonathan Chen u_int8_t *tupledata, u_int32_t start, u_int32_t *off, 5340c95c705SJonathan Chen struct tuple_callbacks *callbacks) 5357bec1dd5SJonathan Chen { 5367bec1dd5SJonathan Chen int i; 5370c95c705SJonathan Chen for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) { 5380c95c705SJonathan Chen if (tupleid == callbacks[i].id) 539255b159fSJonathan Chen return callbacks[i].func(cbdev, child, tupleid, len, 540255b159fSJonathan Chen tupledata, start, off, &callbacks[i]); 5417bec1dd5SJonathan Chen } 5427bec1dd5SJonathan Chen 54349f158ccSJonathan Chen if (tupleid < CISTPL_CUSTOMSTART) { 544255b159fSJonathan Chen device_printf(cbdev, "Undefined tuple encountered, " 545255b159fSJonathan Chen "CIS parsing terminated\n"); 54649f158ccSJonathan Chen return EINVAL; 54749f158ccSJonathan Chen } 548255b159fSJonathan Chen return callbacks[i].func(cbdev, child, tupleid, len, 549255b159fSJonathan Chen tupledata, start, off, NULL); 5500db7e66cSJonathan Chen } 5510db7e66cSJonathan Chen 5520c95c705SJonathan Chen static int 553255b159fSJonathan Chen cardbus_parse_cis(device_t cbdev, device_t child, 5540c95c705SJonathan Chen struct tuple_callbacks *callbacks) 5550db7e66cSJonathan Chen { 5560db7e66cSJonathan Chen u_int8_t tupledata[MAXTUPLESIZE]; 5577bec1dd5SJonathan Chen int tupleid; 5587bec1dd5SJonathan Chen int len; 5597bec1dd5SJonathan Chen int expect_linktarget; 56049f158ccSJonathan Chen u_int32_t start, off; 56163fa9f4cSJonathan Chen struct resource *res; 56263fa9f4cSJonathan Chen int rid; 5630db7e66cSJonathan Chen 5640db7e66cSJonathan Chen bzero(tupledata, MAXTUPLESIZE); 5657bec1dd5SJonathan Chen expect_linktarget = TRUE; 56649f158ccSJonathan Chen start = pci_read_config(child, CARDBUS_CIS_REG, 4); 56749f158ccSJonathan Chen off = 0; 56863fa9f4cSJonathan Chen res = cardbus_read_tuple_init(cbdev, child, &start, &rid); 56963fa9f4cSJonathan Chen if (res == NULL) 57063fa9f4cSJonathan Chen return ENXIO; 5717bec1dd5SJonathan Chen do { 57263fa9f4cSJonathan Chen if (0 != cardbus_read_tuple(cbdev, child, res, start, &off, 57363fa9f4cSJonathan Chen &tupleid, &len, tupledata)) { 57463fa9f4cSJonathan Chen device_printf(cbdev, "Failed to read CIS.\n"); 57563fa9f4cSJonathan Chen cardbus_read_tuple_finish(cbdev, child, rid, res); 57663fa9f4cSJonathan Chen return ENXIO; 57763fa9f4cSJonathan Chen } 5787bec1dd5SJonathan Chen 5797bec1dd5SJonathan Chen if (expect_linktarget && tupleid != CISTPL_LINKTARGET) { 580255b159fSJonathan Chen device_printf(cbdev, "Expecting link target, got 0x%x\n", 5817bec1dd5SJonathan Chen tupleid); 58263fa9f4cSJonathan Chen cardbus_read_tuple_finish(cbdev, child, rid, res); 5837bec1dd5SJonathan Chen return EINVAL; 5847bec1dd5SJonathan Chen } 585255b159fSJonathan Chen expect_linktarget = decode_tuple(cbdev, child, tupleid, len, 58663fa9f4cSJonathan Chen tupledata, start, &off, callbacks); 58763fa9f4cSJonathan Chen if (expect_linktarget != 0) { 58863fa9f4cSJonathan Chen cardbus_read_tuple_finish(cbdev, child, rid, res); 5897bec1dd5SJonathan Chen return expect_linktarget; 59063fa9f4cSJonathan Chen } 5917bec1dd5SJonathan Chen } while (tupleid != CISTPL_END); 59263fa9f4cSJonathan Chen cardbus_read_tuple_finish(cbdev, child, rid, res); 5937bec1dd5SJonathan Chen return 0; 5940db7e66cSJonathan Chen } 5950db7e66cSJonathan Chen 59663fa9f4cSJonathan Chen static int 59763fa9f4cSJonathan Chen barsort(const void *a, const void *b) 59863fa9f4cSJonathan Chen { 59963fa9f4cSJonathan Chen return (*(const struct resource_list_entry **)b)->count - 60063fa9f4cSJonathan Chen (*(const struct resource_list_entry **)a)->count; 60163fa9f4cSJonathan Chen } 60263fa9f4cSJonathan Chen 60363fa9f4cSJonathan Chen static int 60463fa9f4cSJonathan Chen cardbus_alloc_resources(device_t cbdev, device_t child) 60563fa9f4cSJonathan Chen { 60663fa9f4cSJonathan Chen struct cardbus_devinfo *dinfo = device_get_ivars(child); 60763fa9f4cSJonathan Chen int count; 60863fa9f4cSJonathan Chen struct resource_list_entry *rle; 60963fa9f4cSJonathan Chen struct resource_list_entry **barlist; 61063fa9f4cSJonathan Chen int tmp; 61163fa9f4cSJonathan Chen u_int32_t mem_psize = 0, mem_nsize = 0, io_size = 0; 61263fa9f4cSJonathan Chen struct resource *res; 61363fa9f4cSJonathan Chen u_int32_t start,end; 61463fa9f4cSJonathan Chen int rid, flags; 61563fa9f4cSJonathan Chen 61663fa9f4cSJonathan Chen count = 0; 61763fa9f4cSJonathan Chen SLIST_FOREACH(rle, &dinfo->resources, link) { 61863fa9f4cSJonathan Chen count++; 61963fa9f4cSJonathan Chen } 62063fa9f4cSJonathan Chen if (count == 0) 62163fa9f4cSJonathan Chen return 0; 62263fa9f4cSJonathan Chen barlist = malloc(sizeof(struct resource_list_entry*) * count, M_DEVBUF, 62363fa9f4cSJonathan Chen M_WAITOK); 62463fa9f4cSJonathan Chen count = 0; 62563fa9f4cSJonathan Chen SLIST_FOREACH(rle, &dinfo->resources, link) { 62663fa9f4cSJonathan Chen barlist[count] = rle; 62763fa9f4cSJonathan Chen if (rle->type == SYS_RES_IOPORT) { 62863fa9f4cSJonathan Chen io_size += rle->count; 62963fa9f4cSJonathan Chen } else if (rle->type == SYS_RES_MEMORY) { 63063fa9f4cSJonathan Chen if (dinfo->mprefetchable & BARBIT(rle->rid)) 63163fa9f4cSJonathan Chen mem_psize += rle->count; 63263fa9f4cSJonathan Chen else 63363fa9f4cSJonathan Chen mem_nsize += rle->count; 63463fa9f4cSJonathan Chen } 63563fa9f4cSJonathan Chen count++; 63663fa9f4cSJonathan Chen } 63763fa9f4cSJonathan Chen 63863fa9f4cSJonathan Chen /* 63963fa9f4cSJonathan Chen * We want to allocate the largest resource first, so that our 64063fa9f4cSJonathan Chen * allocated memory is packed. 64163fa9f4cSJonathan Chen */ 64263fa9f4cSJonathan Chen qsort(barlist, count, sizeof(struct resource_list_entry*), barsort); 64363fa9f4cSJonathan Chen 64463fa9f4cSJonathan Chen /* Allocate prefetchable memory */ 64563fa9f4cSJonathan Chen flags = 0; 64663fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 64763fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL && 64863fa9f4cSJonathan Chen barlist[tmp]->type == SYS_RES_MEMORY && 64963fa9f4cSJonathan Chen dinfo->mprefetchable & BARBIT(barlist[tmp]->rid)) { 65063fa9f4cSJonathan Chen flags = rman_make_alignment_flags(barlist[tmp]->count); 65163fa9f4cSJonathan Chen break; 65263fa9f4cSJonathan Chen } 65363fa9f4cSJonathan Chen } 65463fa9f4cSJonathan Chen if (flags > 0) { /* If any prefetchable memory is requested... */ 65563fa9f4cSJonathan Chen /* 65663fa9f4cSJonathan Chen * First we allocate one big space for all resources of this 65763fa9f4cSJonathan Chen * type. We do this because our parent, pccbb, needs to open 65863fa9f4cSJonathan Chen * a window to forward all addresses within the window, and 65963fa9f4cSJonathan Chen * it would be best if nobody else has resources allocated 66063fa9f4cSJonathan Chen * within the window. 66163fa9f4cSJonathan Chen * (XXX: Perhaps there might be a better way to do this?) 66263fa9f4cSJonathan Chen */ 66363fa9f4cSJonathan Chen rid = 0; 66463fa9f4cSJonathan Chen res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0, 66563fa9f4cSJonathan Chen (dinfo->mprefetchable & dinfo->mbelow1mb)?0xFFFFF:~0UL, 66663fa9f4cSJonathan Chen mem_psize, flags); 66763fa9f4cSJonathan Chen start = rman_get_start(res); 66863fa9f4cSJonathan Chen end = rman_get_end(res); 66963fa9f4cSJonathan Chen DEVPRINTF((cbdev, "Prefetchable memory at %x-%x\n", start, end)); 67063fa9f4cSJonathan Chen /* 67163fa9f4cSJonathan Chen * Now that we know the region is free, release it and hand it 67263fa9f4cSJonathan Chen * out piece by piece. 67363fa9f4cSJonathan Chen */ 67463fa9f4cSJonathan Chen bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res); 67563fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 67663fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL && 67763fa9f4cSJonathan Chen barlist[tmp]->type == SYS_RES_MEMORY && 67863fa9f4cSJonathan Chen dinfo->mprefetchable & BARBIT(barlist[tmp]->rid)) { 67963fa9f4cSJonathan Chen barlist[tmp]->res = bus_alloc_resource(cbdev, 68063fa9f4cSJonathan Chen barlist[tmp]->type, 68163fa9f4cSJonathan Chen &barlist[tmp]->rid, start, end, 68263fa9f4cSJonathan Chen barlist[tmp]->count, 68363fa9f4cSJonathan Chen rman_make_alignment_flags( 68463fa9f4cSJonathan Chen barlist[tmp]->count)); 68563fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL) { 68663fa9f4cSJonathan Chen mem_nsize += barlist[tmp]->count; 68763fa9f4cSJonathan Chen dinfo->mprefetchable &= 68863fa9f4cSJonathan Chen ~BARBIT(barlist[tmp]->rid); 68963fa9f4cSJonathan Chen DEVPRINTF((cbdev, "Cannot pre-allocate " 69063fa9f4cSJonathan Chen "prefetchable memory, will try as " 69163fa9f4cSJonathan Chen "non-prefetchable.\n")); 69263fa9f4cSJonathan Chen } else { 69363fa9f4cSJonathan Chen barlist[tmp]->start = 69463fa9f4cSJonathan Chen rman_get_start(barlist[tmp]->res); 69563fa9f4cSJonathan Chen barlist[tmp]->end = 69663fa9f4cSJonathan Chen rman_get_end(barlist[tmp]->res); 69763fa9f4cSJonathan Chen pci_write_config(child, 69863fa9f4cSJonathan Chen barlist[tmp]->rid, 69963fa9f4cSJonathan Chen barlist[tmp]->start, 4); 70063fa9f4cSJonathan Chen DEVPRINTF((cbdev, "Prefetchable memory " 70163fa9f4cSJonathan Chen "rid=%x at %lx-%lx\n", 70263fa9f4cSJonathan Chen barlist[tmp]->rid, 70363fa9f4cSJonathan Chen barlist[tmp]->start, 70463fa9f4cSJonathan Chen barlist[tmp]->end)); 70563fa9f4cSJonathan Chen } 70663fa9f4cSJonathan Chen } 70763fa9f4cSJonathan Chen } 70863fa9f4cSJonathan Chen } 70963fa9f4cSJonathan Chen 71063fa9f4cSJonathan Chen /* Allocate non-prefetchable memory */ 71163fa9f4cSJonathan Chen flags = 0; 71263fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 71363fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL && 71463fa9f4cSJonathan Chen barlist[tmp]->type == SYS_RES_MEMORY) { 71563fa9f4cSJonathan Chen flags = rman_make_alignment_flags(barlist[tmp]->count); 71663fa9f4cSJonathan Chen break; 71763fa9f4cSJonathan Chen } 71863fa9f4cSJonathan Chen } 71963fa9f4cSJonathan Chen if (flags > 0) { /* If any non-prefetchable memory is requested... */ 72063fa9f4cSJonathan Chen /* 72163fa9f4cSJonathan Chen * First we allocate one big space for all resources of this 72263fa9f4cSJonathan Chen * type. We do this because our parent, pccbb, needs to open 72363fa9f4cSJonathan Chen * a window to forward all addresses within the window, and 72463fa9f4cSJonathan Chen * it would be best if nobody else has resources allocated 72563fa9f4cSJonathan Chen * within the window. 72663fa9f4cSJonathan Chen * (XXX: Perhaps there might be a better way to do this?) 72763fa9f4cSJonathan Chen */ 72863fa9f4cSJonathan Chen rid = 0; 72963fa9f4cSJonathan Chen res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0, 73063fa9f4cSJonathan Chen ((~dinfo->mprefetchable) & dinfo->mbelow1mb)?0xFFFFF:~0UL, 73163fa9f4cSJonathan Chen mem_nsize, flags); 73263fa9f4cSJonathan Chen start = rman_get_start(res); 73363fa9f4cSJonathan Chen end = rman_get_end(res); 73463fa9f4cSJonathan Chen DEVPRINTF((cbdev, "Non-prefetchable memory at %x-%x\n", 73563fa9f4cSJonathan Chen start, end)); 73663fa9f4cSJonathan Chen /* 73763fa9f4cSJonathan Chen * Now that we know the region is free, release it and hand it 73863fa9f4cSJonathan Chen * out piece by piece. 73963fa9f4cSJonathan Chen */ 74063fa9f4cSJonathan Chen bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res); 74163fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 74263fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL && 74363fa9f4cSJonathan Chen barlist[tmp]->type == SYS_RES_MEMORY) { 74463fa9f4cSJonathan Chen barlist[tmp]->res = bus_alloc_resource(cbdev, 74563fa9f4cSJonathan Chen barlist[tmp]->type, &barlist[tmp]->rid, 74663fa9f4cSJonathan Chen start, end, barlist[tmp]->count, 74763fa9f4cSJonathan Chen rman_make_alignment_flags( 74863fa9f4cSJonathan Chen barlist[tmp]->count)); 74963fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL) { 75063fa9f4cSJonathan Chen DEVPRINTF((cbdev, "Cannot pre-allocate " 75163fa9f4cSJonathan Chen "memory for cardbus device\n")); 75263fa9f4cSJonathan Chen return ENOMEM; 75363fa9f4cSJonathan Chen } 75463fa9f4cSJonathan Chen barlist[tmp]->start = 75563fa9f4cSJonathan Chen rman_get_start(barlist[tmp]->res); 75663fa9f4cSJonathan Chen barlist[tmp]->end = rman_get_end( 75763fa9f4cSJonathan Chen barlist[tmp]->res); 75863fa9f4cSJonathan Chen pci_write_config(child, barlist[tmp]->rid, 75963fa9f4cSJonathan Chen barlist[tmp]->start, 4); 76063fa9f4cSJonathan Chen DEVPRINTF((cbdev, "Non-prefetchable memory " 76163fa9f4cSJonathan Chen "rid=%x at %lx-%lx (%lx)\n", 76263fa9f4cSJonathan Chen barlist[tmp]->rid, barlist[tmp]->start, 76363fa9f4cSJonathan Chen barlist[tmp]->end, barlist[tmp]->count)); 76463fa9f4cSJonathan Chen } 76563fa9f4cSJonathan Chen } 76663fa9f4cSJonathan Chen } 76763fa9f4cSJonathan Chen 76863fa9f4cSJonathan Chen /* Allocate IO ports */ 76963fa9f4cSJonathan Chen flags = 0; 77063fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 77163fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL && 77263fa9f4cSJonathan Chen barlist[tmp]->type == SYS_RES_IOPORT) { 77363fa9f4cSJonathan Chen flags = rman_make_alignment_flags(barlist[tmp]->count); 77463fa9f4cSJonathan Chen break; 77563fa9f4cSJonathan Chen } 77663fa9f4cSJonathan Chen } 77763fa9f4cSJonathan Chen if (flags > 0) { /* If any IO port is requested... */ 77863fa9f4cSJonathan Chen /* 77963fa9f4cSJonathan Chen * First we allocate one big space for all resources of this 78063fa9f4cSJonathan Chen * type. We do this because our parent, pccbb, needs to open 78163fa9f4cSJonathan Chen * a window to forward all addresses within the window, and 78263fa9f4cSJonathan Chen * it would be best if nobody else has resources allocated 78363fa9f4cSJonathan Chen * within the window. 78463fa9f4cSJonathan Chen * (XXX: Perhaps there might be a better way to do this?) 78563fa9f4cSJonathan Chen */ 78663fa9f4cSJonathan Chen rid = 0; 78763fa9f4cSJonathan Chen res = bus_alloc_resource(cbdev, SYS_RES_IOPORT, &rid, 0, 78863fa9f4cSJonathan Chen (dinfo->ibelow1mb)?0xFFFFF:~0UL, io_size, flags); 78963fa9f4cSJonathan Chen start = rman_get_start(res); 79063fa9f4cSJonathan Chen end = rman_get_end(res); 79163fa9f4cSJonathan Chen DEVPRINTF((cbdev, "IO port at %x-%x\n", start, end)); 79263fa9f4cSJonathan Chen /* 79363fa9f4cSJonathan Chen * Now that we know the region is free, release it and hand it 79463fa9f4cSJonathan Chen * out piece by piece. 79563fa9f4cSJonathan Chen */ 79663fa9f4cSJonathan Chen bus_release_resource(cbdev, SYS_RES_IOPORT, rid, res); 79763fa9f4cSJonathan Chen for (tmp = 0; tmp < count; tmp++) { 79863fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL && 79963fa9f4cSJonathan Chen barlist[tmp]->type == SYS_RES_IOPORT) { 80063fa9f4cSJonathan Chen barlist[tmp]->res = bus_alloc_resource(cbdev, 80163fa9f4cSJonathan Chen barlist[tmp]->type, &barlist[tmp]->rid, 80263fa9f4cSJonathan Chen start, end, barlist[tmp]->count, 80363fa9f4cSJonathan Chen rman_make_alignment_flags( 80463fa9f4cSJonathan Chen barlist[tmp]->count)); 80563fa9f4cSJonathan Chen if (barlist[tmp]->res == NULL) { 80663fa9f4cSJonathan Chen DEVPRINTF((cbdev, "Cannot pre-allocate " 80763fa9f4cSJonathan Chen "IO port for cardbus device\n")); 80863fa9f4cSJonathan Chen return ENOMEM; 80963fa9f4cSJonathan Chen } 81063fa9f4cSJonathan Chen barlist[tmp]->start = 81163fa9f4cSJonathan Chen rman_get_start(barlist[tmp]->res); 81263fa9f4cSJonathan Chen barlist[tmp]->end = 81363fa9f4cSJonathan Chen rman_get_end(barlist[tmp]->res); 81463fa9f4cSJonathan Chen pci_write_config(child, barlist[tmp]->rid, 81563fa9f4cSJonathan Chen barlist[tmp]->start, 4); 81663fa9f4cSJonathan Chen DEVPRINTF((cbdev, "IO port rid=%x at %lx-%lx\n", 81763fa9f4cSJonathan Chen barlist[tmp]->rid, barlist[tmp]->start, 81863fa9f4cSJonathan Chen barlist[tmp]->end)); 81963fa9f4cSJonathan Chen } 82063fa9f4cSJonathan Chen } 82163fa9f4cSJonathan Chen } 82263fa9f4cSJonathan Chen 82363fa9f4cSJonathan Chen /* Allocate IRQ */ 82463fa9f4cSJonathan Chen /* XXX: Search CIS for IRQ description */ 82563fa9f4cSJonathan Chen rid = 0; 82663fa9f4cSJonathan Chen res = bus_alloc_resource(cbdev, SYS_RES_IRQ, &rid, 0, ~0UL, 1, 82763fa9f4cSJonathan Chen RF_SHAREABLE); 82863fa9f4cSJonathan Chen resource_list_add(&dinfo->resources, SYS_RES_IRQ, rid, 82963fa9f4cSJonathan Chen rman_get_start(res), rman_get_end(res), 1); 83063fa9f4cSJonathan Chen rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, rid); 83163fa9f4cSJonathan Chen rle->res = res; 83263fa9f4cSJonathan Chen dinfo->cfg.intline = rman_get_start(res); 83363fa9f4cSJonathan Chen pci_write_config(child, PCIR_INTLINE, rman_get_start(res), 1); 83463fa9f4cSJonathan Chen 83563fa9f4cSJonathan Chen return 0; 83663fa9f4cSJonathan Chen } 83763fa9f4cSJonathan Chen 83863fa9f4cSJonathan Chen /* 83963fa9f4cSJonathan Chen * Adding a memory/io resource (sans CIS) 84063fa9f4cSJonathan Chen */ 84163fa9f4cSJonathan Chen 84263fa9f4cSJonathan Chen static void 84363fa9f4cSJonathan Chen cardbus_add_map(device_t cbdev, device_t child, int reg) 84463fa9f4cSJonathan Chen { 84563fa9f4cSJonathan Chen struct cardbus_devinfo *dinfo = device_get_ivars(child); 84663fa9f4cSJonathan Chen struct resource_list_entry *rle; 84763fa9f4cSJonathan Chen u_int32_t size; 84863fa9f4cSJonathan Chen u_int32_t testval; 84963fa9f4cSJonathan Chen int type; 85063fa9f4cSJonathan Chen 85163fa9f4cSJonathan Chen SLIST_FOREACH(rle, &dinfo->resources, link) { 85263fa9f4cSJonathan Chen if (rle->rid == reg) 85363fa9f4cSJonathan Chen return; 85463fa9f4cSJonathan Chen } 85563fa9f4cSJonathan Chen 85663fa9f4cSJonathan Chen if (reg == CARDBUS_ROM_REG) 85763fa9f4cSJonathan Chen testval = CARDBUS_ROM_ADDRMASK; 85863fa9f4cSJonathan Chen else 85963fa9f4cSJonathan Chen testval = ~0; 86063fa9f4cSJonathan Chen 86163fa9f4cSJonathan Chen pci_write_config(child, reg, testval, 4); 86263fa9f4cSJonathan Chen testval = pci_read_config(child, reg, 4); 86363fa9f4cSJonathan Chen 86463fa9f4cSJonathan Chen if (testval == ~0 || testval == 0) 86563fa9f4cSJonathan Chen return; 86663fa9f4cSJonathan Chen 86763fa9f4cSJonathan Chen if ((testval & 1) == 0) 86863fa9f4cSJonathan Chen type = SYS_RES_MEMORY; 86963fa9f4cSJonathan Chen else 87063fa9f4cSJonathan Chen type = SYS_RES_IOPORT; 87163fa9f4cSJonathan Chen 87263fa9f4cSJonathan Chen size = CARDBUS_MAPREG_MEM_SIZE(testval); 87363fa9f4cSJonathan Chen device_printf(cbdev, "Resource not specified in CIS: id=%x, size=%x\n", 87463fa9f4cSJonathan Chen reg, size); 87563fa9f4cSJonathan Chen resource_list_add(&dinfo->resources, type, reg, 0UL, ~0UL, size); 87663fa9f4cSJonathan Chen } 87763fa9f4cSJonathan Chen 87863fa9f4cSJonathan Chen static void 87963fa9f4cSJonathan Chen cardbus_pickup_maps(device_t cbdev, device_t child) 88063fa9f4cSJonathan Chen { 88163fa9f4cSJonathan Chen struct cardbus_devinfo *dinfo = device_get_ivars(child); 88263fa9f4cSJonathan Chen struct cardbus_quirk *q; 88363fa9f4cSJonathan Chen int reg; 88463fa9f4cSJonathan Chen 88563fa9f4cSJonathan Chen /* 88663fa9f4cSJonathan Chen * Try to pick up any resources that was not specified in CIS. 88763fa9f4cSJonathan Chen * Some devices (eg, 3c656) does not list all resources required by 88863fa9f4cSJonathan Chen * the driver in its CIS. 88963fa9f4cSJonathan Chen * XXX: should we do this or use quirks? 89063fa9f4cSJonathan Chen */ 89163fa9f4cSJonathan Chen for (reg = 0; reg < dinfo->cfg.nummaps; reg++) { 89263fa9f4cSJonathan Chen cardbus_add_map(cbdev, child, PCIR_MAPS + reg * 4); 89363fa9f4cSJonathan Chen } 89463fa9f4cSJonathan Chen 89563fa9f4cSJonathan Chen for (q = &cardbus_quirks[0]; q->devid; q++) { 89663fa9f4cSJonathan Chen if (q->devid == ((dinfo->cfg.device << 16) | dinfo->cfg.vendor) 89763fa9f4cSJonathan Chen && q->type == CARDBUS_QUIRK_MAP_REG) { 89863fa9f4cSJonathan Chen cardbus_add_map(cbdev, child, q->arg1); 89963fa9f4cSJonathan Chen } 90063fa9f4cSJonathan Chen } 90163fa9f4cSJonathan Chen } 90263fa9f4cSJonathan Chen 9030c95c705SJonathan Chen int 904255b159fSJonathan Chen cardbus_cis_read(device_t cbdev, device_t child, u_int8_t id, 9050c95c705SJonathan Chen struct cis_tupleinfo **buff, int *nret) 9060c95c705SJonathan Chen { 9070c95c705SJonathan Chen struct tuple_callbacks cisread_callbacks[] = { 9080c95c705SJonathan Chen MAKETUPLE(NULL, nothing), 9090c95c705SJonathan Chen /* first entry will be overwritten */ 9100c95c705SJonathan Chen MAKETUPLE(NULL, nothing), 9110c95c705SJonathan Chen MAKETUPLE(DEVICE, nothing), 9120c95c705SJonathan Chen MAKETUPLE(LONG_LINK_CB, unhandled), 9130c95c705SJonathan Chen MAKETUPLE(INDIRECT, unhandled), 9140c95c705SJonathan Chen MAKETUPLE(CONFIG_CB, nothing), 9150c95c705SJonathan Chen MAKETUPLE(CFTABLE_ENTRY_CB, nothing), 9160c95c705SJonathan Chen MAKETUPLE(LONGLINK_MFC, unhandled), 9170c95c705SJonathan Chen MAKETUPLE(BAR, nothing), 9180c95c705SJonathan Chen MAKETUPLE(PWR_MGMNT, nothing), 9190c95c705SJonathan Chen MAKETUPLE(EXTDEVICE, nothing), 9200c95c705SJonathan Chen MAKETUPLE(CHECKSUM, nothing), 9210c95c705SJonathan Chen MAKETUPLE(LONGLINK_A, unhandled), 9220c95c705SJonathan Chen MAKETUPLE(LONGLINK_C, unhandled), 9230c95c705SJonathan Chen MAKETUPLE(LINKTARGET, nothing), 9240c95c705SJonathan Chen MAKETUPLE(NO_LINK, nothing), 9250c95c705SJonathan Chen MAKETUPLE(VERS_1, nothing), 9260c95c705SJonathan Chen MAKETUPLE(ALTSTR, nothing), 9270c95c705SJonathan Chen MAKETUPLE(DEVICE_A, nothing), 9280c95c705SJonathan Chen MAKETUPLE(JEDEC_C, nothing), 9290c95c705SJonathan Chen MAKETUPLE(JEDEC_A, nothing), 9300c95c705SJonathan Chen MAKETUPLE(CONFIG, nothing), 9310c95c705SJonathan Chen MAKETUPLE(CFTABLE_ENTRY, nothing), 9320c95c705SJonathan Chen MAKETUPLE(DEVICE_OC, nothing), 9330c95c705SJonathan Chen MAKETUPLE(DEVICE_OA, nothing), 9340c95c705SJonathan Chen MAKETUPLE(DEVICE_GEO, nothing), 9350c95c705SJonathan Chen MAKETUPLE(DEVICE_GEO_A, nothing), 9360c95c705SJonathan Chen MAKETUPLE(MANFID, nothing), 9370c95c705SJonathan Chen MAKETUPLE(FUNCID, nothing), 9380c95c705SJonathan Chen MAKETUPLE(FUNCE, nothing), 9390c95c705SJonathan Chen MAKETUPLE(SWIL, nothing), 9400c95c705SJonathan Chen MAKETUPLE(VERS_2, nothing), 9410c95c705SJonathan Chen MAKETUPLE(FORMAT, nothing), 9420c95c705SJonathan Chen MAKETUPLE(GEOMETRY, nothing), 9430c95c705SJonathan Chen MAKETUPLE(BYTEORDER, nothing), 9440c95c705SJonathan Chen MAKETUPLE(DATE, nothing), 9450c95c705SJonathan Chen MAKETUPLE(BATTERY, nothing), 9460c95c705SJonathan Chen MAKETUPLE(ORG, nothing), 9470c95c705SJonathan Chen MAKETUPLE(END, end), 9480c95c705SJonathan Chen MAKETUPLE(GENERIC, nothing), 9490c95c705SJonathan Chen }; 9500c95c705SJonathan Chen int ret; 9510c95c705SJonathan Chen 9520c95c705SJonathan Chen cisread_callbacks[0].id = id; 9530c95c705SJonathan Chen cisread_callbacks[0].name = "COPY"; 9540c95c705SJonathan Chen cisread_callbacks[0].func = decode_tuple_copy; 9550c95c705SJonathan Chen ncisread_buf = 0; 9560c95c705SJonathan Chen cisread_buf = NULL; 957255b159fSJonathan Chen ret = cardbus_parse_cis(cbdev, child, cisread_callbacks); 9580c95c705SJonathan Chen 9590c95c705SJonathan Chen *buff = cisread_buf; 9600c95c705SJonathan Chen *nret = ncisread_buf; 9610c95c705SJonathan Chen return ret; 9620c95c705SJonathan Chen } 9630c95c705SJonathan Chen 9640c95c705SJonathan Chen void 965255b159fSJonathan Chen cardbus_cis_free(device_t cbdev, struct cis_tupleinfo *buff, int *nret) 9660c95c705SJonathan Chen { 9670c95c705SJonathan Chen int i; 9686f39832cSPeter Wemm for (i = 0; i < *nret; i++) 9690c95c705SJonathan Chen free(buff[i].data, M_DEVBUF); 9706f39832cSPeter Wemm if (*nret > 0) 9710c95c705SJonathan Chen free(buff, M_DEVBUF); 9720c95c705SJonathan Chen } 9730c95c705SJonathan Chen 9740c95c705SJonathan Chen int 975255b159fSJonathan Chen cardbus_do_cis(device_t cbdev, device_t child) 9760c95c705SJonathan Chen { 97763fa9f4cSJonathan Chen int ret; 9780c95c705SJonathan Chen struct tuple_callbacks init_callbacks[] = { 9790c95c705SJonathan Chen MAKETUPLE(NULL, generic), 9800c95c705SJonathan Chen MAKETUPLE(DEVICE, generic), 9810c95c705SJonathan Chen MAKETUPLE(LONG_LINK_CB, unhandled), 9820c95c705SJonathan Chen MAKETUPLE(INDIRECT, unhandled), 9830c95c705SJonathan Chen MAKETUPLE(CONFIG_CB, generic), 9840c95c705SJonathan Chen MAKETUPLE(CFTABLE_ENTRY_CB, generic), 9850c95c705SJonathan Chen MAKETUPLE(LONGLINK_MFC, unhandled), 9860c95c705SJonathan Chen MAKETUPLE(BAR, bar), 9870c95c705SJonathan Chen MAKETUPLE(PWR_MGMNT, generic), 9880c95c705SJonathan Chen MAKETUPLE(EXTDEVICE, generic), 9890c95c705SJonathan Chen MAKETUPLE(CHECKSUM, generic), 9900c95c705SJonathan Chen MAKETUPLE(LONGLINK_A, unhandled), 9910c95c705SJonathan Chen MAKETUPLE(LONGLINK_C, unhandled), 9920c95c705SJonathan Chen MAKETUPLE(LINKTARGET, linktarget), 9930c95c705SJonathan Chen MAKETUPLE(NO_LINK, generic), 9940c95c705SJonathan Chen MAKETUPLE(VERS_1, vers_1), 9950c95c705SJonathan Chen MAKETUPLE(ALTSTR, generic), 9960c95c705SJonathan Chen MAKETUPLE(DEVICE_A, generic), 9970c95c705SJonathan Chen MAKETUPLE(JEDEC_C, generic), 9980c95c705SJonathan Chen MAKETUPLE(JEDEC_A, generic), 9990c95c705SJonathan Chen MAKETUPLE(CONFIG, generic), 10000c95c705SJonathan Chen MAKETUPLE(CFTABLE_ENTRY, generic), 10010c95c705SJonathan Chen MAKETUPLE(DEVICE_OC, generic), 10020c95c705SJonathan Chen MAKETUPLE(DEVICE_OA, generic), 10030c95c705SJonathan Chen MAKETUPLE(DEVICE_GEO, generic), 10040c95c705SJonathan Chen MAKETUPLE(DEVICE_GEO_A, generic), 10050c95c705SJonathan Chen MAKETUPLE(MANFID, manfid), 10060c95c705SJonathan Chen MAKETUPLE(FUNCID, funcid), 10070c95c705SJonathan Chen MAKETUPLE(FUNCE, funce), 10080c95c705SJonathan Chen MAKETUPLE(SWIL, generic), 10090c95c705SJonathan Chen MAKETUPLE(VERS_2, generic), 10100c95c705SJonathan Chen MAKETUPLE(FORMAT, generic), 10110c95c705SJonathan Chen MAKETUPLE(GEOMETRY, generic), 10120c95c705SJonathan Chen MAKETUPLE(BYTEORDER, generic), 10130c95c705SJonathan Chen MAKETUPLE(DATE, generic), 10140c95c705SJonathan Chen MAKETUPLE(BATTERY, generic), 10150c95c705SJonathan Chen MAKETUPLE(ORG, generic), 10160c95c705SJonathan Chen MAKETUPLE(END, end), 10170c95c705SJonathan Chen MAKETUPLE(GENERIC, generic), 10180c95c705SJonathan Chen }; 101963fa9f4cSJonathan Chen 102063fa9f4cSJonathan Chen ret = cardbus_parse_cis(cbdev, child, init_callbacks); 102163fa9f4cSJonathan Chen if (ret < 0) 102263fa9f4cSJonathan Chen return ret; 102363fa9f4cSJonathan Chen cardbus_pickup_maps(cbdev, child); 102463fa9f4cSJonathan Chen return cardbus_alloc_resources(cbdev, child); 10250c95c705SJonathan Chen } 1026