gen_path_callouts: Create multi-segment callouts
The BMC FSI segments will be connected to other FSI segments to create
new FSI callouts as far out as there is a path, and all the FSI callouts
will be connected with any I2C or SPI segments to create new FSII2C or
FSISPI callouts. For example, there could be a Callout object that
contains the path of: BMC -> FSI -> Proc -> FSI -> Proc -> I2C ->
end device.
When the new Callout objects are created from two other callout objects,
the FRU callout lists will be cumulative. In a future commit, they will
be sorted and made unique.
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: Id1aeb02ead755a876a25f28341c4693762b8b86a
diff --git a/gen_path_callouts.pl b/gen_path_callouts.pl
index 1662e6f..9f357fb 100755
--- a/gen_path_callouts.pl
+++ b/gen_path_callouts.pl
@@ -149,6 +149,67 @@
return $self->{SPIBus};
}
+# FSII2CCallout object for FSI-I2C callouts
+# Ideally this would be derived from FSICallout, but I can't
+# get it to work.
+package FSII2CCallout;
+
+our @ISA = qw(Callout);
+sub new
+{
+ my ($class) = @_;
+ # source, dest, calloutList
+ my $self = $class->SUPER::new("FSI-I2C", $_[1], $_[2], $_[3]);
+ $self->{FSILink} = $_[4];
+ $self->{i2cBus} = $_[5];
+ $self->{i2cAddr} = $_[6];
+ return bless $self, $class;
+}
+
+sub fsiLink
+{
+ my $self = shift;
+ return $self->{FSILink};
+}
+
+sub i2cBus
+{
+ my $self = shift;
+ return $self->{i2cBus};
+}
+
+sub i2cAddress
+{
+ my $self = shift;
+ return $self->{i2cAddr};
+}
+
+#FSISPICallout object for FSI-SPI callouts
+package FSISPICallout;
+
+our @ISA = qw(Callout);
+sub new
+{
+ my ($class) = @_;
+ # source, dest, calloutList
+ my $self = $class->SUPER::new("FSI-SPI", $_[1], $_[2], $_[3]);
+ $self->{FSILink} = $_[4];
+ $self->{SPIBus} = $_[5];
+ return bless $self, $class;
+}
+
+sub fsiLink
+{
+ my $self = shift;
+ return $self->{FSILink};
+}
+
+sub spiBus
+{
+ my $self = shift;
+ return $self->{SPIBus};
+}
+
package main;
use mrw::Targets;
@@ -388,6 +449,9 @@
# Callouts for 1 segment connections directly off of the BMC.
buildBMCSingleSegmentCallouts($segments, $callouts);
+
+ # Callouts more than 1 segment away
+ buildMultiSegmentCallouts($segments, $callouts);
}
# Build the callout objects for devices 1 segment away.
@@ -435,6 +499,130 @@
return undef;
}
+# Build the callout objects for devices more than 1 segment away from
+# the BMC. All but the last segment will always be FSI. The FRU
+# callouts accumulate as segments are added.
+sub buildMultiSegmentCallouts
+{
+ my ($segments, $callouts) = @_;
+ my $hops = 0;
+ my $found = 1;
+
+ # Connect FSI link callouts to other FSI segments to make new callouts, and
+ # connect all FSI link callouts up with the I2C/SPI segments to make even
+ # more new callouts. Note: Deal with I2C muxes, if they are ever modeled,
+ # when there are some.
+
+ # Each time through the loop, go out another FSI hop.
+ # Stop when no more new hops are found.
+ while ($found)
+ {
+ my @newCallouts;
+ $found = 0;
+
+ for my $callout (@$callouts)
+ {
+ if ($callout->type() ne "FSI")
+ {
+ next;
+ }
+
+ # link numbers are separated by '-'s in the link field,
+ # so 0-5 = 1 hop
+ my @numHops = $callout->fsiLink() =~ /(-)/g;
+
+ # only deal with callout objects that contain $hops hops.
+ if ($hops != scalar @numHops)
+ {
+ next;
+ }
+
+ for my $segmentType (keys %$segments)
+ {
+ for my $segment (@{$$segments{$segmentType}})
+ {
+ # If the destination on this callout is the same
+ # as the source of the segment, then make a new
+ # callout that spans both.
+ if ($callout->destChip() eq $segment->{SourceChip})
+ {
+ # First build the new single segment callout
+ my $segmentCallout =
+ buildSingleSegmentCallout($segment);
+
+ # Now merge both callouts into one.
+ if (defined $segmentCallout)
+ {
+ my $newCallout =
+ mergeCallouts($callout, $segmentCallout);
+
+ push @newCallouts, $newCallout;
+ $found = 1;
+ }
+ }
+ }
+ }
+ }
+
+ if ($found)
+ {
+ push @{$callouts}, @newCallouts;
+ }
+
+ $hops = $hops + 1;
+ }
+}
+
+# Merge 2 callout objects into 1 that contains all of their FRU callouts.
+sub mergeCallouts
+{
+ my ($firstCallout, $secondCallout) = @_;
+
+ # This callout list will be merged/sorted later.
+ # Endpoint callouts are added first, so they will be higher
+ # in the callout list (priority permitting).
+ my @calloutList;
+ push @calloutList, @{$secondCallout->calloutList()};
+ push @calloutList, @{$firstCallout->calloutList()};
+
+ # FSI
+ if (($firstCallout->type() eq "FSI") && ($secondCallout->type() eq "FSI"))
+ {
+ # combine the FSI links with a -
+ my $FSILink = $firstCallout->fsiLink() . "-" .
+ $secondCallout->fsiLink();
+
+ my $fsiCallout = new FSICallout($firstCallout->sourceChip(),
+ $secondCallout->destChip(), \@calloutList, $FSILink);
+
+ return $fsiCallout;
+ }
+ # FSI-I2C
+ elsif (($firstCallout->type() eq "FSI") &&
+ ($secondCallout->type() eq "I2C"))
+ {
+ my $i2cCallout = new FSII2CCallout($firstCallout->sourceChip(),
+ $secondCallout->destChip(), \@calloutList,
+ $firstCallout->fsiLink(), $secondCallout->i2cBus(),
+ $secondCallout->i2cAddress());
+
+ return $i2cCallout;
+ }
+ # FSI-SPI
+ elsif (($firstCallout->type() eq "FSI") &&
+ ($secondCallout->type() eq "SPI"))
+ {
+ my $spiCallout = new FSISPICallout($firstCallout->sourceChip(),
+ $secondCallout->destChip(), \@calloutList,
+ $firstCallout->fsiLink(), $secondCallout->spiBus());
+
+ return $spiCallout;
+ }
+
+ die "Unrecognized callouts to merge: " . $firstCallout->type() .
+ " " . $secondCallout->type() . "\n";
+}
+
# Create an I2CCallout object
sub createI2CCallout
{