# HG changeset patch # User rw148561 # Date 1171615921 28800 # Node ID ecc47116246b12243ee01820fb9fa77fe75bc09a # Parent 718327411bfa0e8cec8bddef5b3c77bee5e46d3d 6522697 cardbus should work better under subtractive decode bridge 6460235 pcic does not recognize "pciex" bus_type 6516884 pcic_add_debqueue() could cause panic under memory shortage diff -r 718327411bfa -r ecc47116246b usr/src/uts/common/io/cardbus/cardbus_cfg.c --- a/usr/src/uts/common/io/cardbus/cardbus_cfg.c Thu Feb 15 15:33:40 2007 -0800 +++ b/usr/src/uts/common/io/cardbus/cardbus_cfg.c Fri Feb 16 00:52:01 2007 -0800 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* @@ -45,6 +45,7 @@ #include #include +#include #include @@ -131,6 +132,7 @@ struct cardbus_phdl { dev_info_t *dip; /* Associated with the attach point */ + dev_info_t *res_dip; /* dip from which io/mem is allocated */ cardbus_phdl_t *next; uint64_t memory_base; /* Memory base for this attach point */ @@ -551,6 +553,7 @@ { cardbus_phdl_t *entry; cardbus_phdl_t *follow = NULL; + ra_return_t res; mutex_enter(&cardbus_list_mutex); for (entry = cardbus_phdl_list; entry != NULL; follow = entry, @@ -567,9 +570,9 @@ * must be freed up. */ if (entry->memory_len > 0) { - (void) ndi_ra_free(dip, - entry->memory_base, entry->memory_len, - NDI_RA_TYPE_MEM, NDI_RA_PASS); + res.ra_addr_lo = entry->memory_base; + res.ra_len = entry->memory_len; + (void) pcmcia_free_mem(entry->res_dip, &res); #ifdef _LP64 cardbus_err(dip, 8, "cardbus_destroy_phdl: " @@ -583,9 +586,9 @@ #endif } if (entry->io_len > 0) { - (void) ndi_ra_free(dip, - entry->io_base, entry->io_len, - NDI_RA_TYPE_IO, NDI_RA_PASS); + res.ra_addr_lo = entry->io_base; + res.ra_len = entry->io_len; + (void) pcmcia_free_io(entry->res_dip, &res); cardbus_err(dip, 8, "cardbus_destroy_phdl: " "IO BASE = [0x%x] length [0x%x]\n", @@ -1170,10 +1173,8 @@ cardbus_phdl_t *phdl; ndi_ra_request_t *mem_request; ndi_ra_request_t *io_request; - uint64_t mem_answer; - uint64_t io_answer; + ra_return_t res; int count; - uint64_t alen; /* * This should not find an existing entry - so @@ -1248,15 +1249,15 @@ mem_request->ra_len); #endif - if (ndi_ra_alloc(dip, mem_request, &mem_answer, &alen, - NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) { + if (pcmcia_alloc_mem(dip, mem_request, &res, + &phdl->res_dip) != NDI_SUCCESS) { cmn_err(CE_WARN, "Failed to allocate memory for %s\n", ddi_driver_name(dip)); return (PCICFG_FAILURE); } - phdl->memory_base = phdl->memory_last = mem_answer; - phdl->memory_len = alen; + phdl->memory_base = phdl->memory_last = res.ra_addr_lo; + phdl->memory_len = res.ra_len; } io_request->ra_len += cardbus_min_spare_io; @@ -1272,21 +1273,24 @@ io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED; io_request->ra_len = PCICFG_ROUND_UP(io_request->ra_len, phdl->io_gran); - - if (ndi_ra_alloc(dip, io_request, &io_answer, - &alen, NDI_RA_TYPE_IO, NDI_RA_PASS) != NDI_SUCCESS) { + io_request->ra_align_mask = max(PCICFG_IOGRAN, + phdl->io_gran) - 1; + + if (pcmcia_alloc_io(dip, io_request, &res, + &phdl->res_dip) != NDI_SUCCESS) { cmn_err(CE_WARN, "Failed to allocate I/O space " "for %s\n", ddi_driver_name(dip)); if (mem_request->ra_len) { - (void) ndi_ra_free(dip, mem_answer, - alen, NDI_RA_TYPE_MEM, NDI_RA_PASS); + res.ra_addr_lo = phdl->memory_base; + res.ra_len = phdl->memory_len; + (void) pcmcia_free_mem(phdl->res_dip, &res); phdl->memory_len = phdl->io_len = 0; } return (PCICFG_FAILURE); } - phdl->io_base = phdl->io_last = (uint32_t)io_answer; - phdl->io_len = (uint32_t)alen; + phdl->io_base = phdl->io_last = (uint32_t)res.ra_addr_lo; + phdl->io_len = (uint32_t)res.ra_len; } #ifdef _LP64 diff -r 718327411bfa -r ecc47116246b usr/src/uts/common/io/pcic.c --- a/usr/src/uts/common/io/pcic.c Thu Feb 15 15:33:40 2007 -0800 +++ b/usr/src/uts/common/io/pcic.c Fri Feb 16 00:52:01 2007 -0800 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -812,7 +812,8 @@ } } /* ddi_prop_op("device_type") */ - if (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0) { + if (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0 || + strcmp(bus_type, DEVI_PCIEX_NEXNAME) == 0) { pcic->pc_flags = PCF_PCIBUS; } else { #if defined(__sparc) @@ -2128,7 +2129,7 @@ (uint32_t *)(pcic->cfgaddr + PCIC_MFROUTE_REG)); value &= ~0xff; ddi_put32(pcic->cfg_handle, (uint32_t *)(pcic->cfgaddr + - PCIC_MFROUTE_REG), value|0x22); + PCIC_MFROUTE_REG), value|PCIC_TI_MFUNC_SEL); } /* setup general card status change interrupt */ @@ -2810,7 +2811,7 @@ ddi_regs_map_free(&memp->pcw_handle); res.ra_addr_lo = memp->pcw_base; res.ra_len = memp->pcw_len; - (void) pcmcia_free_mem(dip, &res); + (void) pcmcia_free_mem(memp->res_dip, &res); memp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED); memp->pcw_hostmem = NULL; memp->pcw_base = NULL; @@ -2845,7 +2846,8 @@ req.ra_align_mask); #endif - ret = pcmcia_alloc_mem(dip, &req, &res); + ret = pcmcia_alloc_mem(dip, &req, &res, + &memp->res_dip); if (ret == DDI_FAILURE) { mutex_exit(&pcic->pc_lock); cmn_err(CE_WARN, @@ -2880,7 +2882,7 @@ res.ra_addr_lo = memp->pcw_base; res.ra_len = memp->pcw_len; - (void) pcmcia_free_mem(pcic->dip, &res); + (void) pcmcia_free_mem(memp->res_dip, &res); mutex_exit(&pcic->pc_lock); @@ -3091,7 +3093,7 @@ ddi_regs_map_free(&memp->pcw_handle); res.ra_addr_lo = memp->pcw_base; res.ra_len = memp->pcw_len; - (void) pcmcia_free_mem(pcic->dip, &res); + (void) pcmcia_free_mem(memp->res_dip, &res); memp->pcw_hostmem = NULL; memp->pcw_status &= ~PCW_MAPPED; } @@ -3146,7 +3148,7 @@ ddi_regs_map_free(&winp->pcw_handle); res.ra_addr_lo = winp->pcw_base; res.ra_len = winp->pcw_len; - (void) pcmcia_free_io(pcic->dip, &res); + (void) pcmcia_free_io(winp->res_dip, &res); winp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED); } @@ -3212,7 +3214,8 @@ * on whether the caller specified a * specific base address or not. */ - if (pcmcia_alloc_io(dip, &req, &res) == DDI_FAILURE) { + if (pcmcia_alloc_io(dip, &req, &res, + &winp->res_dip) == DDI_FAILURE) { winp->pcw_status &= ~PCW_ENABLED; mutex_exit(&pcic->pc_lock); cmn_err(CE_WARN, "Failed to alloc I/O:\n" @@ -3257,7 +3260,7 @@ res.ra_addr_lo = winp->pcw_base; res.ra_len = winp->pcw_len; - (void) pcmcia_free_io(pcic->dip, &res); + (void) pcmcia_free_io(winp->res_dip, &res); mutex_exit(&pcic->pc_lock); return (BAD_WINDOW); @@ -3431,7 +3434,7 @@ ddi_regs_map_free(&winp->pcw_handle); res.ra_addr_lo = winp->pcw_base; res.ra_len = winp->pcw_len; - (void) pcmcia_free_io(pcic->dip, &res); + (void) pcmcia_free_io(winp->res_dip, &res); winp->pcw_status &= ~PCW_MAPPED; } @@ -5911,7 +5914,8 @@ DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "device_type", (caddr_t)&bus_type, &len) == DDI_SUCCESS) && - (strcmp(bus_type, "pci") == 0)) + (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0 || + strcmp(bus_type, DEVI_PCIEX_NEXNAME) == 0)) break; } if (par != NULL && @@ -6491,7 +6495,7 @@ struct debounce *dbp, **dbpp = &pcic_deb_queue; (void) drv_getparm(LBOLT, &lbolt); - dbp = kmem_alloc(sizeof (struct debounce), KM_NOSLEEP); + dbp = kmem_alloc(sizeof (struct debounce), KM_SLEEP); dbp->expire = lbolt + clocks; dbp->pcs = pcs; diff -r 718327411bfa -r ecc47116246b usr/src/uts/common/pcmcia/nexus/pcmcia.c --- a/usr/src/uts/common/pcmcia/nexus/pcmcia.c Thu Feb 15 15:33:40 2007 -0800 +++ b/usr/src/uts/common/pcmcia/nexus/pcmcia.c Fri Feb 16 00:52:01 2007 -0800 @@ -196,6 +196,8 @@ sizeof (char *)) #define PCMCIA_MAP_IO 0x0 #define PCMCIA_MAP_MEM 0x1 +#define PPB_SUBTRACTIVE ((PCI_CLASS_BRIDGE << 16) | (PCI_BRIDGE_PCI << 8) | \ + (PCI_BRIDGE_PCI_IF_SUBDECODE)) /* * The following should be 2^^n - 1 @@ -237,7 +239,8 @@ static void pcmcia_ppd_free(struct pcmcia_parent_private *ppd); int pcmcia_get_intr(dev_info_t *, int); int pcmcia_return_intr(dev_info_t *, int); -int pcmcia_ra_alloc(dev_info_t *, ndi_ra_request_t *, ra_return_t *, char *); +int pcmcia_ra_alloc(dev_info_t *, ndi_ra_request_t *, ra_return_t *, char *, + dev_info_t **); int pcmcia_ra_free(dev_info_t *, ra_return_t *, char *); extern int cs_init(void); @@ -4452,22 +4455,83 @@ } int -pcmcia_alloc_mem(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret) +pcmcia_alloc_mem(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret, + dev_info_t **res_dip) { - return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_MEM)); + return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_MEM, res_dip)); } int -pcmcia_alloc_io(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret) +pcmcia_alloc_io(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret, + dev_info_t **res_dip) +{ + return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_IO, res_dip)); +} + +static boolean_t +is_subtractv(dev_info_t *dip) { - return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_IO)); + uint_t class; + + if (dip == NULL) + return (B_FALSE); + class = ddi_getprop(DDI_DEV_T_ANY, dip, + DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS, + "class-code", 0xff); + if (class == PPB_SUBTRACTIVE) { + return (B_TRUE); + } + return (B_FALSE); +} + +/* + * pcmcia_pci_alloc() + * allocate mem or I/O resource from the ancestor of the cardbus bridge. + * First start from the parent node. If the parent is a subtractive + * decode bridge and it does not have the requested resource, go up the + * device tree to find the resource. + * + * dip the parent node of the cardbus bridge + * + * res_dip returns a pointer to the node from which the + * resource is obtained. *res_dip could point to + * the parent or a higher level ancestor. *res_dip + * should be saved by the caller and later passed + * to pcmcia_ra_free(); + */ +int +pcmcia_pci_alloc(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret, + char *type, dev_info_t **res_dip) +{ + uint64_t base = 0; + uint64_t len = 0; + + if ((ndi_ra_alloc(dip, req, &base, &len, type, NDI_RA_PASS) + == NDI_FAILURE) || + ((base >> 32) != 0)) { + if (is_subtractv(dip)) { + return (pcmcia_pci_alloc(ddi_get_parent(dip), + req, ret, type, res_dip)); + + } else { + ret->ra_addr_hi = 0; + ret->ra_addr_lo = 0; + ret->ra_len = 0; + *res_dip = (dev_info_t *)-1; + return (DDI_FAILURE); + } + } + ret->ra_addr_lo = base & 0xffffffff; + ret->ra_addr_hi = 0; + ret->ra_len = len; + *res_dip = dip; + return (DDI_SUCCESS); } int pcmcia_ra_alloc(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret, - char *type) + char *type, dev_info_t **res_dip) { - int rval; uint64_t base = 0; uint64_t len = 0; @@ -4479,16 +4543,15 @@ if ((ndi_ra_alloc(dip, req, &base, &len, type, NDI_RA_PASS) == NDI_FAILURE) || ((base >> 32) != 0)) { - ret->ra_addr_lo = 0; - ret->ra_len = 0; - rval = DDI_FAILURE; + return (pcmcia_pci_alloc(ddi_get_parent(dip), req, ret, + type, res_dip)); } else { ret->ra_addr_lo = base & 0xffffffff; + ret->ra_addr_hi = 0; ret->ra_len = len; - rval = DDI_SUCCESS; + *res_dip = dip; + return (DDI_SUCCESS); } - ret->ra_addr_hi = 0; - return (rval); } int diff -r 718327411bfa -r ecc47116246b usr/src/uts/common/sys/pcic_var.h --- a/usr/src/uts/common/sys/pcic_var.h Thu Feb 15 15:33:40 2007 -0800 +++ b/usr/src/uts/common/sys/pcic_var.h Fri Feb 16 00:52:01 2007 -0800 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -79,6 +79,7 @@ volatile caddr_t pcw_hostmem; off_t pcw_offset; ddi_acc_handle_t pcw_handle; + dev_info_t *res_dip; /* dip from which mem is allocated */ } pcs_memwin_t; typedef struct pci_iowin { @@ -90,6 +91,7 @@ /* Cirrus Logic specific offset info */ int pcw_offset; ddi_acc_handle_t pcw_handle; + dev_info_t *res_dip; /* dip from which io is allocated */ } pcs_iowin_t; #define PCW_MAPPED 0x0001 /* window is mapped */ @@ -540,6 +542,10 @@ #define PCIC_DATA_LOST 0x100 /* Data lost */ #define PCIC_BAD_VCC_REQ 0x200 /* Bad Vcc request */ + +/* TI Multi Function Terminal selection (MFUNC0 selected as INTA) */ +#define PCIC_TI_MFUNC_SEL 0x22 + #define PCICPROP_CTL "controller" #define PCIC_REV_LEVEL_LOW 0x02 @@ -554,6 +560,10 @@ #define DEVI_PCI_NEXNAME "pci" #endif +#ifndef DEVI_PCIEX_NEXNAME +#define DEVI_PCIEX_NEXNAME "pciex" +#endif + /* PCI Class Code stuff */ #define PCIC_PCI_CLASS(cls, subclass) (((cls) << 16) | ((subclass) << 8)) #define PCIC_PCI_PCMCIA PCIC_PCI_CLASS(PCI_CLASS_BRIDGE, PCI_BRIDGE_PCMCIA) diff -r 718327411bfa -r ecc47116246b usr/src/uts/common/sys/sservice.h --- a/usr/src/uts/common/sys/sservice.h Thu Feb 15 15:33:40 2007 -0800 +++ b/usr/src/uts/common/sys/sservice.h Fri Feb 16 00:52:01 2007 -0800 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -570,8 +569,10 @@ uint_t ra_len; } ra_return_t; -int pcmcia_alloc_mem(dev_info_t *, ndi_ra_request_t *, ra_return_t *); -int pcmcia_alloc_io(dev_info_t *, ndi_ra_request_t *, ra_return_t *); +int pcmcia_alloc_mem(dev_info_t *, ndi_ra_request_t *, ra_return_t *, + dev_info_t **); +int pcmcia_alloc_io(dev_info_t *, ndi_ra_request_t *, ra_return_t *, + dev_info_t **); int pcmcia_free_mem(dev_info_t *, ra_return_t *); int pcmcia_free_io(dev_info_t *, ra_return_t *); int pcmcia_map_reg(dev_info_t *, dev_info_t *, ra_return_t *,