lkml.org 
[lkml]   [2005]   [Jun]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: pci_enable_msi() for everyone?
Greg KH wrote:
> In talking with a few people about the MSI kernel code, they asked why
> we can't just do the pci_enable_msi() call for every pci device in the
> system (at somewhere like pci_enable_device() time or so). That would
> let all drivers and devices get the MSI functionality without changing
> their code, and probably make the api a whole lot simpler.

Agreed.

And now is a good time to make changes, before bunches of drivers start
using pci_enable_msi(). I am preparing such a change for the AHCI
driver (see attached), which will be the standard SATA interface on most
new motherboards.


> Now I know the e1000 driver would have to specifically disable MSI for
> some of their broken versions, and possibly some other drivers might
> need this, but the downside seems quite small.

tg3 needs to deal with some broken system chipsets as well. See
tg3_test_msi(), which I would eventually prefer to eliminate in favor of
PCI quirks and such.

An API note of warning though... IMO eventually different drivers are
going to want different behavior from pci_enable_device(). IDE already
hacks around this, as Alan was required to do a while ago (IDE has a
weird PCI BAR setup sometimes, requiring care during enabling).

Longer term, I think we will need a

pci_enable(info on what to enable)

so that drivers can specify ahead of time "don't enable PIO, only MMIO",
"don't enable MMIO, only PIO", "don't use MSI", etc. and add a
pci_disable() to undo all of that.

The more we add singleton functions like pci_enable_msi(),
pci_set_master(), etc. the more I wish for a single function that
handled all those details at one atomic point. There is a lot of
standard patterns that are hand-coded into every PCI driver's probe
functions.

Jeff

diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -39,7 +39,7 @@
#include <asm/io.h>

#define DRV_NAME "ahci"
-#define DRV_VERSION "1.00"
+#define DRV_VERSION "1.01"


enum {
@@ -153,6 +153,7 @@ struct ahci_sg {

struct ahci_host_priv {
unsigned long flags;
+ unsigned int have_msi; /* is PCI MSI enabled? */
u32 cap; /* cache of HOST_CAP register */
u32 port_map; /* cache of HOST_PORTS_IMPL reg */
};
@@ -183,6 +184,7 @@ static void ahci_qc_prep(struct ata_queu
static u8 ahci_check_status(struct ata_port *ap);
static u8 ahci_check_err(struct ata_port *ap);
static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
+static void ahci_remove_one (struct pci_dev *pdev);

static Scsi_Host_Template ahci_sht = {
.module = THIS_MODULE,
@@ -272,7 +274,7 @@ static struct pci_driver ahci_pci_driver
.name = DRV_NAME,
.id_table = ahci_pci_tbl,
.probe = ahci_init_one,
- .remove = ata_pci_remove_one,
+ .remove = ahci_remove_one,
};


@@ -879,15 +881,19 @@ static int ahci_host_init(struct ata_pro
}

/* move to PCI layer, integrate w/ MSI stuff */
-static void pci_enable_intx(struct pci_dev *pdev)
+static void pci_intx(struct pci_dev *pdev, int enable)
{
- u16 pci_command;
+ u16 pci_command, new;

pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
- if (pci_command & PCI_COMMAND_INTX_DISABLE) {
- pci_command &= ~PCI_COMMAND_INTX_DISABLE;
+
+ if (enable)
+ new = pci_command & ~PCI_COMMAND_INTX_DISABLE;
+ else
+ new = pci_command | PCI_COMMAND_INTX_DISABLE;
+
+ if (new != pci_command)
pci_write_config_word(pdev, PCI_COMMAND, pci_command);
- }
}

static void ahci_print_info(struct ata_probe_ent *probe_ent)
@@ -969,7 +975,7 @@ static int ahci_init_one (struct pci_dev
unsigned long base;
void *mmio_base;
unsigned int board_idx = (unsigned int) ent->driver_data;
- int pci_dev_busy = 0;
+ int have_msi, pci_dev_busy = 0;
int rc;

VPRINTK("ENTER\n");
@@ -987,12 +993,17 @@ static int ahci_init_one (struct pci_dev
goto err_out;
}

- pci_enable_intx(pdev);
+ if (pci_enable_msi(pdev) == 0)
+ have_msi = 1;
+ else {
+ pci_intx(pdev, 1);
+ have_msi = 0;
+ }

probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
if (probe_ent == NULL) {
rc = -ENOMEM;
- goto err_out_regions;
+ goto err_out_msi;
}

memset(probe_ent, 0, sizeof(*probe_ent));
@@ -1025,6 +1036,8 @@ static int ahci_init_one (struct pci_dev
probe_ent->mmio_base = mmio_base;
probe_ent->private_data = hpriv;

+ hpriv->have_msi = have_msi;
+
/* initialize adapter */
rc = ahci_host_init(probe_ent);
if (rc)
@@ -1044,7 +1057,11 @@ err_out_iounmap:
iounmap(mmio_base);
err_out_free_ent:
kfree(probe_ent);
-err_out_regions:
+err_out_msi:
+ if (have_msi)
+ pci_disable_msi(pdev);
+ else
+ pci_intx(pdev, 0);
pci_release_regions(pdev);
err_out:
if (!pci_dev_busy)
@@ -1052,6 +1069,42 @@ err_out:
return rc;
}

+static void ahci_remove_one (struct pci_dev *pdev)
+{
+ struct device *dev = pci_dev_to_dev(pdev);
+ struct ata_host_set *host_set = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host_set->private_data;
+ struct ata_port *ap;
+ unsigned int i;
+ int have_msi;
+
+ for (i = 0; i < host_set->n_ports; i++) {
+ ap = host_set->ports[i];
+
+ scsi_remove_host(ap->host);
+ }
+
+ have_msi = hpriv->have_msi;
+ free_irq(host_set->irq, host_set);
+
+ for (i = 0; i < host_set->n_ports; i++) {
+ ap = host_set->ports[i];
+
+ ata_scsi_release(ap->host);
+ scsi_host_put(ap->host);
+ }
+
+ host_set->ops->host_stop(host_set);
+ kfree(host_set);
+
+ if (have_msi)
+ pci_disable_msi(pdev);
+ else
+ pci_intx(pdev, 0);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ dev_set_drvdata(dev, NULL);
+}

static int __init ahci_init(void)
{
\
 
 \ /
  Last update: 2005-06-04 01:19    [W:0.878 / U:0.092 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site