IPMI: Detect register spacing on PCI interfaces
authorCorey Minyard <cminyard@mvista.com>
Tue, 16 Oct 2012 20:53:40 +0000 (15:53 -0500)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 17 Oct 2012 01:07:12 +0000 (18:07 -0700)
The IPMI spec defines a way to detect register spacing for PCI interfaces,
so implement it.

Signed-off-by: Steven Hsieh <sshsieh@broadcom.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/char/ipmi/ipmi_si_intf.c

index 83f85cf7fb1b424afd4dde0b104af0ea21a51f7b..32a6c7e256bd82496f7461999a7ea3408342f423 100644 (file)
@@ -2424,6 +2424,38 @@ static void ipmi_pci_cleanup(struct smi_info *info)
        pci_disable_device(pdev);
 }
 
+static int __devinit ipmi_pci_probe_regspacing(struct smi_info *info)
+{
+       if (info->si_type == SI_KCS) {
+               unsigned char   status;
+               int             regspacing;
+
+               info->io.regsize = DEFAULT_REGSIZE;
+               info->io.regshift = 0;
+               info->io_size = 2;
+               info->handlers = &kcs_smi_handlers;
+
+               /* detect 1, 4, 16byte spacing */
+               for (regspacing = DEFAULT_REGSPACING; regspacing <= 16;) {
+                       info->io.regspacing = regspacing;
+                       if (info->io_setup(info)) {
+                               dev_err(info->dev,
+                                       "Could not setup I/O space\n");
+                               return DEFAULT_REGSPACING;
+                       }
+                       /* write invalid cmd */
+                       info->io.outputb(&info->io, 1, 0x10);
+                       /* read status back */
+                       status = info->io.inputb(&info->io, 1);
+                       info->io_cleanup(info);
+                       if (status)
+                               return regspacing;
+                       regspacing *= 4;
+               }
+       }
+       return DEFAULT_REGSPACING;
+}
+
 static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
                                    const struct pci_device_id *ent)
 {
@@ -2476,8 +2508,8 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
        }
        info->io.addr_data = pci_resource_start(pdev, 0);
 
-       info->io.regspacing = DEFAULT_REGSPACING;
-       info->io.regsize = DEFAULT_REGSPACING;
+       info->io.regspacing = ipmi_pci_probe_regspacing(info);
+       info->io.regsize = DEFAULT_REGSIZE;
        info->io.regshift = 0;
 
        info->irq = pdev->irq;