Subject: Re: CardBus PCI
To: None <mcr@sandelman.ottawa.on.ca>
From: Hayakawa Koichi <haya@ilink.sony.co.jp>
List: tech-kern
Date: 04/25/2001 12:32:00
Hello,

From: Michael Richardson <mcr@sandelman.ottawa.on.ca>
Subject: Re: CardBus PCI 
Date: Tue, 24 Apr 2001 14:30:41 -0400
Message-ID: <200104241830.f3OIUfh14054@marajade.sandelman.ottawa.on.ca>

 >   As I look through things, I think that we need to adjust the way that
 > PCI devices establish interrupts, or at least hack pci_intr_map
 > to realize that it is behind a cardbus bridge.

We should assign correct intrrupt-line-number to
pba_intrline, at least for i386.  I attach a patch at the
end of this mail (Sorry I don't compile it, because I have
no NetBSD machine on me now).  This patch intends to write
cardbus's interrupt line number on all PCI funtion's
interrupt line registers.

# I don't know why sc_intrswiz is needed;-)

 
 >   The more that I think about it, the more that I think that we need
 > a new value for pci_chipset_tag_t. Does this make sense?

Yes, logically.  But, maybe this value is not used, at least
on i386.
-- 
HAYAKAWA, Koichi

P.S.  I think we should unify PCI and CardBus (and
      CompactPCI, possibly) handler, but...


*** rbus_ppb.c	Wed Apr 25 11:58:38 2001
--- rbus_ppb.c	Wed Apr 25 12:29:21 2001
***************
*** 163,168 ****
--- 163,169 ----
          char devinfo[256];
          pcireg_t busdata;
          int mybus;
+ 	int device, function, nfunctions;
  
          mybus = ct->ct_bus;
  
***************
*** 207,216 ****
  	pba.pba_pc   = psc->sc_pc;
  	pba.pba_flags    = PCI_FLAGS_IO_ENABLED|PCI_FLAGS_MEM_ENABLED;
  	pba.pba_bus      = PPB_BUSINFO_SECONDARY(busdata);
! 	/*pba.pba_intrswiz = 0 ca->ca_intrswiz*/;
! 	/*pba.pba_intrtag  = psc->sc_intrtag;*/
! 	/*pba.pba_intrline = parent_sc->sc_intrline; */
  
  	config_found(self, &pba, rppbprint);
  }
  
--- 208,265 ----
          pba.pba_pc   = psc->sc_pc;
          pba.pba_flags    = PCI_FLAGS_IO_ENABLED|PCI_FLAGS_MEM_ENABLED;
          pba.pba_bus      = PPB_BUSINFO_SECONDARY(busdata);
!         pba.pba_intrswiz = 0;
!         pba.pba_intrtag  = 0;
!         pba.pba_intrline = parent_sc->sc_intrline;
  
+ 	for (device = 0; device < 32; device++) {
+ 		pcitag_t tag;
+ 		pcireg_t id, class, intr, bhlcr, csr;
+ 		struct pci_attach_args pa;
+ 		int pin;
+ 
+ 		tag = pci_make_tag(pc, pba.pba_bus, device, 0);
+ 		id = pci_conf_read(pc, tag, PCI_ID_REG);
+ 
+ 		/* Invalid vendor ID value? */
+ 		if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
+ 			continue;
+ 		/* XXX Not invalid, but we've done this ~forever. */
+ 		if (PCI_VENDOR(id) == 0)
+ 			continue;
+ 
+ 		bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
+ 		if (PCI_HDRTYPE_MULTIFN(bhlcr) ||
+ 		    (qd != NULL &&
+ 		      (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
+ 			nfunctions = 8;
+ 		else
+ 			nfunctions = 1;
+ 
+ 		for (function = 0; function < nfunctions; function++) {
+ 			tag = pci_make_tag(pc, pba.pba_bus, device, function);
+ 			id = pci_conf_read(pc, tag, PCI_ID_REG);
+ 
+ 			/* Invalid vendor ID value? */
+ 			if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
+ 				continue;
+ 			/* XXX Not invalid, but we've done this ~forever. */
+ 			if (PCI_VENDOR(id) == 0)
+ 				continue;
+ 
+ 			intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
+ 
+ 			if (PCI_INTERRUPT_PIN(intr) == 0) {
+ 				/* No interrupt required */
+ 				continue;
+ 			}
+ 
+ 			intr &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT);
+ 			intr |= ((PCI_INTERRUPT_LINE_MASK & parent_sc->sc_intrline) << PCI_INTERRUPT_LINE_SHIFT);
+ 			pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr);
+ 		}
+ 	}
+ 
          config_found(self, &pba, rppbprint);
  }