@@ -437,26 +437,37 @@ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,
437437 read_op = bridge -> ops -> read_pcie ;
438438 cfgspace = (__le32 * ) & bridge -> pcie_conf ;
439439 behavior = bridge -> pcie_cap_regs_behavior ;
440- } else {
441- /* Beyond our PCIe space */
440+ } else if ( reg < PCI_CFG_SPACE_SIZE ) {
441+ /* Rest of PCI space not implemented */
442442 * value = 0 ;
443443 return PCIBIOS_SUCCESSFUL ;
444+ } else {
445+ /* PCIe extended capability space */
446+ reg -= PCI_CFG_SPACE_SIZE ;
447+ read_op = bridge -> ops -> read_ext ;
448+ cfgspace = NULL ;
449+ behavior = NULL ;
444450 }
445451
446452 if (read_op )
447453 ret = read_op (bridge , reg , value );
448454 else
449455 ret = PCI_BRIDGE_EMUL_NOT_HANDLED ;
450456
451- if (ret == PCI_BRIDGE_EMUL_NOT_HANDLED )
452- * value = le32_to_cpu (cfgspace [reg / 4 ]);
457+ if (ret == PCI_BRIDGE_EMUL_NOT_HANDLED ) {
458+ if (cfgspace )
459+ * value = le32_to_cpu (cfgspace [reg / 4 ]);
460+ else
461+ * value = 0 ;
462+ }
453463
454464 /*
455465 * Make sure we never return any reserved bit with a value
456466 * different from 0.
457467 */
458- * value &= behavior [reg / 4 ].ro | behavior [reg / 4 ].rw |
459- behavior [reg / 4 ].w1c ;
468+ if (behavior )
469+ * value &= behavior [reg / 4 ].ro | behavior [reg / 4 ].rw |
470+ behavior [reg / 4 ].w1c ;
460471
461472 if (size == 1 )
462473 * value = (* value >> (8 * (where & 3 ))) & 0xff ;
@@ -502,8 +513,15 @@ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
502513 write_op = bridge -> ops -> write_pcie ;
503514 cfgspace = (__le32 * ) & bridge -> pcie_conf ;
504515 behavior = bridge -> pcie_cap_regs_behavior ;
505- } else {
516+ } else if (reg < PCI_CFG_SPACE_SIZE ) {
517+ /* Rest of PCI space not implemented */
506518 return PCIBIOS_SUCCESSFUL ;
519+ } else {
520+ /* PCIe extended capability space */
521+ reg -= PCI_CFG_SPACE_SIZE ;
522+ write_op = bridge -> ops -> write_ext ;
523+ cfgspace = NULL ;
524+ behavior = NULL ;
507525 }
508526
509527 shift = (where & 0x3 ) * 8 ;
@@ -517,29 +535,38 @@ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
517535 else
518536 return PCIBIOS_BAD_REGISTER_NUMBER ;
519537
520- /* Keep all bits, except the RW bits */
521- new = old & (~mask | ~behavior [reg / 4 ].rw );
538+ if (behavior ) {
539+ /* Keep all bits, except the RW bits */
540+ new = old & (~mask | ~behavior [reg / 4 ].rw );
522541
523- /* Update the value of the RW bits */
524- new |= (value << shift ) & (behavior [reg / 4 ].rw & mask );
542+ /* Update the value of the RW bits */
543+ new |= (value << shift ) & (behavior [reg / 4 ].rw & mask );
525544
526- /* Clear the W1C bits */
527- new &= ~((value << shift ) & (behavior [reg / 4 ].w1c & mask ));
545+ /* Clear the W1C bits */
546+ new &= ~((value << shift ) & (behavior [reg / 4 ].w1c & mask ));
547+ } else {
548+ new = old & ~mask ;
549+ new |= (value << shift ) & mask ;
550+ }
528551
529- /* Save the new value with the cleared W1C bits into the cfgspace */
530- cfgspace [reg / 4 ] = cpu_to_le32 (new );
552+ if (cfgspace ) {
553+ /* Save the new value with the cleared W1C bits into the cfgspace */
554+ cfgspace [reg / 4 ] = cpu_to_le32 (new );
555+ }
531556
532- /*
533- * Clear the W1C bits not specified by the write mask, so that the
534- * write_op() does not clear them.
535- */
536- new &= ~(behavior [reg / 4 ].w1c & ~mask );
557+ if (behavior ) {
558+ /*
559+ * Clear the W1C bits not specified by the write mask, so that the
560+ * write_op() does not clear them.
561+ */
562+ new &= ~(behavior [reg / 4 ].w1c & ~mask );
537563
538- /*
539- * Set the W1C bits specified by the write mask, so that write_op()
540- * knows about that they are to be cleared.
541- */
542- new |= (value << shift ) & (behavior [reg / 4 ].w1c & mask );
564+ /*
565+ * Set the W1C bits specified by the write mask, so that write_op()
566+ * knows about that they are to be cleared.
567+ */
568+ new |= (value << shift ) & (behavior [reg / 4 ].w1c & mask );
569+ }
543570
544571 if (write_op )
545572 write_op (bridge , reg , old , new , mask );
0 commit comments