Allow device ID arrays in the PCI driver structure

Many PCI devices share the very same driver despite having different
PCI device IDs, which causes a lot of copy and paste of driver
definitions.

This change introduces a way to specify the array of acceptable
device IDs in a single driver entry. As an example the Intel
{Sandy|Ivy} Bridge SATA driver is being modified to use a single
driver structure for all different SATA controller flavors, a few
more Ivy Bridge IDs are being added as well.

BUG=none
TEST=manual
  . modified coreboot brought up an Ivy Bridge platform all the
    way to Linux login screen.

Change-Id: I761c5611b93ef946053783f7a755e6c456dd6991
Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Reviewed-on: http://review.coreboot.org/982
Tested-by: build bot (Jenkins)
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-by: Patrick Georgi <patrick@georgi-clan.de>
diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c
index c055995..c9af7c4 100644
--- a/src/devices/pci_device.c
+++ b/src/devices/pci_device.c
@@ -796,6 +796,28 @@
 }
 
 /**
+ * Check if a device id matches a PCI driver entry.
+ *
+ * The driver entry can either point at a zero terminated array of acceptable
+ * device IDs, or include a single device ID.
+ *
+ * @driver pointer to the PCI driver entry being checked
+ * @device_id PCI device ID of the device being matched
+ */
+static int device_id_match(struct pci_driver *driver, unsigned short device_id)
+{
+	if (driver->devices) {
+		unsigned short check_id;
+		const unsigned short *device_list = driver->devices;
+		while ((check_id = *device_list++) != 0)
+			if (check_id == device_id)
+				return 1;
+	}
+
+	return (driver->device == device_id);
+}
+
+/**
  * Set up PCI device operation.
  *
  * Check if it already has a driver. If not, use find_device_operations(),
@@ -817,7 +839,7 @@
 	 */
 	for (driver = &pci_drivers[0]; driver != &epci_drivers[0]; driver++) {
 		if ((driver->vendor == dev->vendor) &&
-		    (driver->device == dev->device)) {
+		    device_id_match(driver, dev->device)) {
 			dev->ops = (struct device_operations *)driver->ops;
 			printk(BIOS_SPEW, "%s [%04x/%04x] %sops\n",
 			       dev_path(dev), driver->vendor, driver->device,