summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2009-11-16 15:38:27 +0000
committermav <mav@FreeBSD.org>2009-11-16 15:38:27 +0000
commit0cf423f4bc725573827f0ae2dd6135ff185420b6 (patch)
treeefaf424fe83caf1bc785787b8411630fefbc407d
parentfcc28e89e25a64898f3337bcad9dabf9745665a4 (diff)
downloadFreeBSD-src-0cf423f4bc725573827f0ae2dd6135ff185420b6.zip
FreeBSD-src-0cf423f4bc725573827f0ae2dd6135ff185420b6.tar.gz
Change the way in which AHCI+PATA combined controllers, such as JMicron
and Marvell handled. Instead of trying to attach two different drivers to single device, wrapping each call, make one of them (atajmicron, atamarvell) attach do device solely, but create child device for AHCI driver, passing it all required resources. It is quite easy, as none of resources are shared, except IRQ. As result, it: - makes drivers operation more independent and straitforward, - allows to use new ahci(4) driver with such devices, adding support for new features, such as PMP and NCQ, same time keeping legacy PATA support, - will allow to just drop old ataahci driver, when it's time come.
-rw-r--r--sys/dev/ahci/ahci.c123
-rw-r--r--sys/dev/ahci/ahci.h2
-rw-r--r--sys/dev/ata/ata-pci.c257
-rw-r--r--sys/dev/ata/ata-pci.h19
-rw-r--r--sys/dev/ata/chipsets/ata-ahci.c94
-rw-r--r--sys/dev/ata/chipsets/ata-jmicron.c126
-rw-r--r--sys/dev/ata/chipsets/ata-marvell.c95
7 files changed, 415 insertions, 301 deletions
diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c
index fed095b..2d21c05 100644
--- a/sys/dev/ahci/ahci.c
+++ b/sys/dev/ahci/ahci.c
@@ -99,7 +99,14 @@ MALLOC_DEFINE(M_AHCI, "AHCI driver", "AHCI driver data buffers");
static struct {
uint32_t id;
const char *name;
- int flags;
+ int quirks;
+#define AHCI_Q_NOFORCE 1
+#define AHCI_Q_NOPMP 2
+#define AHCI_Q_NONCQ 4
+#define AHCI_Q_1CH 8
+#define AHCI_Q_2CH 16
+#define AHCI_Q_4CH 32
+#define AHCI_Q_EDGEIS 64
} ahci_ids[] = {
{0x43801002, "ATI IXP600", 0},
{0x43901002, "ATI IXP700", 0},
@@ -145,6 +152,15 @@ static struct {
{0x3b2b8086, "Intel PCH", 0},
{0x3b2c8086, "Intel PCH", 0},
{0x3b2f8086, "Intel PCH", 0},
+ {0x2361197b, "JMicron JMB361", AHCI_Q_NOFORCE},
+ {0x2363197b, "JMicron JMB363", AHCI_Q_NOFORCE},
+ {0x2365197b, "JMicron JMB365", AHCI_Q_NOFORCE},
+ {0x2366197b, "JMicron JMB366", AHCI_Q_NOFORCE},
+ {0x2368197b, "JMicron JMB368", AHCI_Q_NOFORCE},
+ {0x611111ab, "Marvell 88SX6111", AHCI_Q_NOFORCE|AHCI_Q_1CH|AHCI_Q_EDGEIS},
+ {0x612111ab, "Marvell 88SX6121", AHCI_Q_NOFORCE|AHCI_Q_2CH|AHCI_Q_EDGEIS},
+ {0x614111ab, "Marvell 88SX6141", AHCI_Q_NOFORCE|AHCI_Q_4CH|AHCI_Q_EDGEIS},
+ {0x614511ab, "Marvell 88SX6145", AHCI_Q_NOFORCE|AHCI_Q_4CH|AHCI_Q_EDGEIS},
{0x044c10de, "NVIDIA MCP65", 0},
{0x044d10de, "NVIDIA MCP65", 0},
{0x044e10de, "NVIDIA MCP65", 0},
@@ -226,9 +242,39 @@ static int
ahci_probe(device_t dev)
{
char buf[64];
+ int i, valid = 0;
+ uint32_t devid = pci_get_devid(dev);
+
+ /* Is this a possible AHCI candidate? */
+ if (pci_get_class(dev) == PCIC_STORAGE &&
+ pci_get_subclass(dev) == PCIS_STORAGE_SATA &&
+ pci_get_progif(dev) == PCIP_STORAGE_SATA_AHCI_1_0)
+ valid = 1;
+ /* Is this a known AHCI chip? */
+ for (i = 0; ahci_ids[i].id != 0; i++) {
+ if (ahci_ids[i].id == devid &&
+ (valid || !(ahci_ids[i].quirks & AHCI_Q_NOFORCE))) {
+ snprintf(buf, sizeof(buf), "%s AHCI SATA controller",
+ ahci_ids[i].name);
+ device_set_desc_copy(dev, buf);
+ return (BUS_PROBE_VENDOR);
+ }
+ }
+ if (!valid)
+ return (ENXIO);
+ device_set_desc_copy(dev, "AHCI SATA controller");
+ return (BUS_PROBE_VENDOR);
+}
+
+static int
+ahci_ata_probe(device_t dev)
+{
+ char buf[64];
int i;
uint32_t devid = pci_get_devid(dev);
+ if ((intptr_t)device_get_ivars(dev) >= 0)
+ return (ENXIO);
/* Is this a known AHCI chip? */
for (i = 0; ahci_ids[i].id != 0; i++) {
if (ahci_ids[i].id == devid) {
@@ -238,11 +284,6 @@ ahci_probe(device_t dev)
return (BUS_PROBE_VENDOR);
}
}
- /* Is this a possible AHCI candidate? */
- if (pci_get_class(dev) != PCIC_STORAGE ||
- pci_get_subclass(dev) != PCIS_STORAGE_SATA ||
- pci_get_progif(dev) != PCIP_STORAGE_SATA_AHCI_1_0)
- return (ENXIO);
device_set_desc_copy(dev, "AHCI SATA controller");
return (BUS_PROBE_VENDOR);
}
@@ -252,10 +293,15 @@ ahci_attach(device_t dev)
{
struct ahci_controller *ctlr = device_get_softc(dev);
device_t child;
- int error, unit, speed;
+ int error, unit, speed, i;
+ uint32_t devid = pci_get_devid(dev);
u_int32_t version;
ctlr->dev = dev;
+ i = 0;
+ while (ahci_ids[i].id != 0 && ahci_ids[i].id != devid)
+ i++;
+ ctlr->quirks = ahci_ids[i].quirks;
resource_int_value(device_get_name(dev),
device_get_unit(dev), "ccc", &ctlr->ccc);
/* if we have a memory BAR(5) we are likely on an AHCI part */
@@ -282,10 +328,32 @@ ahci_attach(device_t dev)
rman_fini(&ctlr->sc_iomem);
return (error);
};
- /* Get the number of HW channels */
+ /* Get the HW capabilities */
+ version = ATA_INL(ctlr->r_mem, AHCI_VS);
+ ctlr->caps = ATA_INL(ctlr->r_mem, AHCI_CAP);
+ if (version >= 0x00010020)
+ ctlr->caps2 = ATA_INL(ctlr->r_mem, AHCI_CAP2);
ctlr->ichannels = ATA_INL(ctlr->r_mem, AHCI_PI);
+ if (ctlr->quirks & AHCI_Q_1CH) {
+ ctlr->caps &= ~AHCI_CAP_NPMASK;
+ ctlr->ichannels &= 0x01;
+ }
+ if (ctlr->quirks & AHCI_Q_2CH) {
+ ctlr->caps &= ~AHCI_CAP_NPMASK;
+ ctlr->caps |= 1;
+ ctlr->ichannels &= 0x03;
+ }
+ if (ctlr->quirks & AHCI_Q_4CH) {
+ ctlr->caps &= ~AHCI_CAP_NPMASK;
+ ctlr->caps |= 3;
+ ctlr->ichannels &= 0x0f;
+ }
ctlr->channels = MAX(flsl(ctlr->ichannels),
- (ATA_INL(ctlr->r_mem, AHCI_CAP) & AHCI_CAP_NPMASK) + 1);
+ (ctlr->caps & AHCI_CAP_NPMASK) + 1);
+ if (ctlr->quirks & AHCI_Q_NOPMP)
+ ctlr->caps &= ~AHCI_CAP_SPM;
+ if (ctlr->quirks & AHCI_Q_NONCQ)
+ ctlr->caps &= ~AHCI_CAP_SNCQ;
/* Setup interrupts. */
if (ahci_setup_interrupt(dev)) {
bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
@@ -293,10 +361,6 @@ ahci_attach(device_t dev)
return ENXIO;
}
/* Announce HW capabilities. */
- version = ATA_INL(ctlr->r_mem, AHCI_VS);
- ctlr->caps = ATA_INL(ctlr->r_mem, AHCI_CAP);
- if (version >= 0x00010020)
- ctlr->caps2 = ATA_INL(ctlr->r_mem, AHCI_CAP2);
speed = (ctlr->caps & AHCI_CAP_ISS) >> AHCI_CAP_ISS_SHIFT;
device_printf(dev,
"AHCI v%x.%02x with %d %sGbps ports, Port Multiplier %s\n",
@@ -531,8 +595,15 @@ ahci_intr(void *data)
for (; unit < ctlr->channels; unit++) {
if ((is & (1 << unit)) != 0 &&
(arg = ctlr->interrupt[unit].argument)) {
- ctlr->interrupt[unit].function(arg);
- ATA_OUTL(ctlr->r_mem, AHCI_IS, 1 << unit);
+ if (ctlr->quirks & AHCI_Q_EDGEIS) {
+ /* Some controller have edge triggered IS. */
+ ATA_OUTL(ctlr->r_mem, AHCI_IS, 1 << unit);
+ ctlr->interrupt[unit].function(arg);
+ } else {
+ /* but AHCI declares level triggered IS. */
+ ctlr->interrupt[unit].function(arg);
+ ATA_OUTL(ctlr->r_mem, AHCI_IS, 1 << unit);
+ }
}
}
}
@@ -665,6 +736,25 @@ static driver_t ahci_driver = {
sizeof(struct ahci_controller)
};
DRIVER_MODULE(ahci, pci, ahci_driver, ahci_devclass, 0, 0);
+static device_method_t ahci_ata_methods[] = {
+ DEVMETHOD(device_probe, ahci_ata_probe),
+ DEVMETHOD(device_attach, ahci_attach),
+ DEVMETHOD(device_detach, ahci_detach),
+ DEVMETHOD(device_suspend, ahci_suspend),
+ DEVMETHOD(device_resume, ahci_resume),
+ DEVMETHOD(bus_print_child, ahci_print_child),
+ DEVMETHOD(bus_alloc_resource, ahci_alloc_resource),
+ DEVMETHOD(bus_release_resource, ahci_release_resource),
+ DEVMETHOD(bus_setup_intr, ahci_setup_intr),
+ DEVMETHOD(bus_teardown_intr,ahci_teardown_intr),
+ { 0, 0 }
+};
+static driver_t ahci_ata_driver = {
+ "ahci",
+ ahci_ata_methods,
+ sizeof(struct ahci_controller)
+};
+DRIVER_MODULE(ahci, atapci, ahci_ata_driver, ahci_devclass, 0, 0);
MODULE_VERSION(ahci, 1);
MODULE_DEPEND(ahci, cam, 1, 1, 1);
@@ -688,6 +778,7 @@ ahci_ch_attach(device_t dev)
ch->unit = (intptr_t)device_get_ivars(dev);
ch->caps = ctlr->caps;
ch->caps2 = ctlr->caps2;
+ ch->quirks = ctlr->quirks;
ch->numslots = ((ch->caps & AHCI_CAP_NCS) >> AHCI_CAP_NCS_SHIFT) + 1,
mtx_init(&ch->mtx, "AHCI channel lock", NULL, MTX_DEF);
resource_int_value(device_get_name(dev),
@@ -858,7 +949,7 @@ static driver_t ahcich_driver = {
ahcich_methods,
sizeof(struct ahci_channel)
};
-DRIVER_MODULE(ahcich, ahci, ahcich_driver, ahci_devclass, 0, 0);
+DRIVER_MODULE(ahcich, ahci, ahcich_driver, ahcich_devclass, 0, 0);
struct ahci_dc_cb_args {
bus_addr_t maddr;
diff --git a/sys/dev/ahci/ahci.h b/sys/dev/ahci/ahci.h
index 0686f67..cda9078 100644
--- a/sys/dev/ahci/ahci.h
+++ b/sys/dev/ahci/ahci.h
@@ -352,6 +352,7 @@ struct ahci_channel {
struct cam_path *path;
uint32_t caps; /* Controller capabilities */
uint32_t caps2; /* Controller capabilities */
+ int quirks;
int numslots; /* Number of present slots */
int pm_level; /* power management level */
int sata_rev; /* Maximum allowed SATA generation */
@@ -391,6 +392,7 @@ struct ahci_controller {
} irqs[16];
uint32_t caps; /* Controller capabilities */
uint32_t caps2; /* Controller capabilities */
+ int quirks;
int numirqs;
int channels;
int ichannels;
diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c
index 4440bde..4a24455 100644
--- a/sys/dev/ata/ata-pci.c
+++ b/sys/dev/ata/ata-pci.c
@@ -189,91 +189,138 @@ ata_pci_resume(device_t dev)
return error;
}
+int
+ata_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+
+ return (BUS_READ_IVAR(device_get_parent(dev), dev, which, result));
+}
+
+int
+ata_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+
+ return (BUS_WRITE_IVAR(device_get_parent(dev), dev, which, value));
+}
+
+uint32_t
+ata_pci_read_config(device_t dev, device_t child, int reg, int width)
+{
+
+ return (pci_read_config(dev, reg, width));
+}
+
+void
+ata_pci_write_config(device_t dev, device_t child, int reg,
+ uint32_t val, int width)
+{
+
+ pci_write_config(dev, reg, val, width);
+}
+
struct resource *
ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
- struct ata_pci_controller *controller = device_get_softc(dev);
- int unit = ((struct ata_channel *)device_get_softc(child))->unit;
- struct resource *res = NULL;
- int myrid;
-
- if (type == SYS_RES_IOPORT) {
- switch (*rid) {
- case ATA_IOADDR_RID:
- if (controller->legacy) {
- start = (unit ? ATA_SECONDARY : ATA_PRIMARY);
- count = ATA_IOSIZE;
- end = start + count - 1;
- }
- myrid = PCIR_BAR(0) + (unit << 3);
- res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
- SYS_RES_IOPORT, &myrid,
- start, end, count, flags);
- break;
-
- case ATA_CTLADDR_RID:
- if (controller->legacy) {
- start = (unit ? ATA_SECONDARY : ATA_PRIMARY) + ATA_CTLOFFSET;
- count = ATA_CTLIOSIZE;
- end = start + count - 1;
- }
- myrid = PCIR_BAR(1) + (unit << 3);
- res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
- SYS_RES_IOPORT, &myrid,
- start, end, count, flags);
- break;
- }
- }
- if (type == SYS_RES_IRQ && *rid == ATA_IRQ_RID) {
- if (controller->legacy) {
- int irq = (unit == 0 ? 14 : 15);
+ struct ata_pci_controller *controller = device_get_softc(dev);
+ struct resource *res = NULL;
+
+ if (device_get_devclass(child) == ata_devclass) {
+ int unit = ((struct ata_channel *)device_get_softc(child))->unit;
+ int myrid;
+
+ if (type == SYS_RES_IOPORT) {
+ switch (*rid) {
+ case ATA_IOADDR_RID:
+ if (controller->legacy) {
+ start = (unit ? ATA_SECONDARY : ATA_PRIMARY);
+ count = ATA_IOSIZE;
+ end = start + count - 1;
+ }
+ myrid = PCIR_BAR(0) + (unit << 3);
+ res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
+ SYS_RES_IOPORT, &myrid,
+ start, end, count, flags);
+ break;
+ case ATA_CTLADDR_RID:
+ if (controller->legacy) {
+ start = (unit ? ATA_SECONDARY : ATA_PRIMARY) +
+ ATA_CTLOFFSET;
+ count = ATA_CTLIOSIZE;
+ end = start + count - 1;
+ }
+ myrid = PCIR_BAR(1) + (unit << 3);
+ res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
+ SYS_RES_IOPORT, &myrid,
+ start, end, count, flags);
+ break;
+ }
+ }
+ if (type == SYS_RES_IRQ && *rid == ATA_IRQ_RID) {
+ if (controller->legacy) {
+ int irq = (unit == 0 ? 14 : 15);
- res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
- SYS_RES_IRQ, rid, irq, irq, 1, flags);
+ res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
+ SYS_RES_IRQ, rid, irq, irq, 1, flags);
+ } else
+ res = controller->r_irq;
+ }
+ } else {
+ if (type == SYS_RES_IRQ) {
+ if (*rid != ATA_IRQ_RID)
+ return (NULL);
+ res = controller->r_irq;
+ } else {
+ res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
+ type, rid, start, end, count, flags);
+ }
}
- else
- res = controller->r_irq;
- }
- return res;
+ return (res);
}
int
ata_pci_release_resource(device_t dev, device_t child, int type, int rid,
struct resource *r)
{
- struct ata_pci_controller *controller = device_get_softc(dev);
- int unit = ((struct ata_channel *)device_get_softc(child))->unit;
-
- if (type == SYS_RES_IOPORT) {
- switch (rid) {
- case ATA_IOADDR_RID:
- return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev,
- SYS_RES_IOPORT,
- PCIR_BAR(0) + (unit << 3), r);
- break;
-
- case ATA_CTLADDR_RID:
- return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev,
- SYS_RES_IOPORT,
- PCIR_BAR(1) + (unit << 3), r);
- break;
- default:
- return ENOENT;
- }
- }
- if (type == SYS_RES_IRQ) {
- if (rid != ATA_IRQ_RID)
- return ENOENT;
- if (controller->legacy) {
- return BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
- SYS_RES_IRQ, rid, r);
+ if (device_get_devclass(child) == ata_devclass) {
+ struct ata_pci_controller *controller = device_get_softc(dev);
+ int unit = ((struct ata_channel *)device_get_softc(child))->unit;
+
+ if (type == SYS_RES_IOPORT) {
+ switch (rid) {
+ case ATA_IOADDR_RID:
+ return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev,
+ SYS_RES_IOPORT,
+ PCIR_BAR(0) + (unit << 3), r);
+ case ATA_CTLADDR_RID:
+ return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev,
+ SYS_RES_IOPORT,
+ PCIR_BAR(1) + (unit << 3), r);
+ default:
+ return ENOENT;
+ }
+ }
+ if (type == SYS_RES_IRQ) {
+ if (rid != ATA_IRQ_RID)
+ return ENOENT;
+ if (controller->legacy) {
+ return BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
+ SYS_RES_IRQ, rid, r);
+ } else
+ return 0;
+ }
+ } else {
+ if (type == SYS_RES_IRQ) {
+ if (rid != ATA_IRQ_RID)
+ return (ENOENT);
+ return (0);
+ } else {
+ return (BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
+ type, rid, r));
+ }
}
- else
- return 0;
- }
- return EINVAL;
+ return (EINVAL);
}
int
@@ -281,44 +328,50 @@ ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq,
int flags, driver_filter_t *filter, driver_intr_t *function,
void *argument, void **cookiep)
{
- struct ata_pci_controller *controller = device_get_softc(dev);
-
- if (controller->legacy) {
- return BUS_SETUP_INTR(device_get_parent(dev), child, irq,
- flags, filter, function, argument, cookiep);
- }
- else {
struct ata_pci_controller *controller = device_get_softc(dev);
- int unit = ((struct ata_channel *)device_get_softc(child))->unit;
- if (filter != NULL) {
- printf("ata-pci.c: we cannot use a filter here\n");
- return (EINVAL);
+ if (controller->legacy) {
+ return BUS_SETUP_INTR(device_get_parent(dev), child, irq,
+ flags, filter, function, argument, cookiep);
+ } else {
+ struct ata_pci_controller *controller = device_get_softc(dev);
+ int unit;
+
+ if (filter != NULL) {
+ printf("ata-pci.c: we cannot use a filter here\n");
+ return (EINVAL);
+ }
+ if (device_get_devclass(child) == ata_devclass)
+ unit = ((struct ata_channel *)device_get_softc(child))->unit;
+ else
+ unit = ATA_PCI_MAX_CH - 1;
+ controller->interrupt[unit].function = function;
+ controller->interrupt[unit].argument = argument;
+ *cookiep = controller;
+ return 0;
}
- controller->interrupt[unit].function = function;
- controller->interrupt[unit].argument = argument;
- *cookiep = controller;
- return 0;
- }
}
int
ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq,
void *cookie)
{
- struct ata_pci_controller *controller = device_get_softc(dev);
-
- if (controller->legacy) {
- return BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq, cookie);
- }
- else {
struct ata_pci_controller *controller = device_get_softc(dev);
- int unit = ((struct ata_channel *)device_get_softc(child))->unit;
- controller->interrupt[unit].function = NULL;
- controller->interrupt[unit].argument = NULL;
- return 0;
- }
+ if (controller->legacy) {
+ return BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq, cookie);
+ } else {
+ struct ata_pci_controller *controller = device_get_softc(dev);
+ int unit;
+
+ if (device_get_devclass(child) == ata_devclass)
+ unit = ((struct ata_channel *)device_get_softc(child))->unit;
+ else
+ unit = ATA_PCI_MAX_CH - 1;
+ controller->interrupt[unit].function = NULL;
+ controller->interrupt[unit].argument = NULL;
+ return 0;
+ }
}
static void
@@ -510,12 +563,16 @@ static device_method_t ata_pci_methods[] = {
DEVMETHOD(device_shutdown, bus_generic_shutdown),
/* bus methods */
+ DEVMETHOD(bus_read_ivar, ata_pci_read_ivar),
+ DEVMETHOD(bus_write_ivar, ata_pci_write_ivar),
DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource),
DEVMETHOD(bus_release_resource, ata_pci_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
DEVMETHOD(bus_setup_intr, ata_pci_setup_intr),
DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr),
+ DEVMETHOD(pci_read_config, ata_pci_read_config),
+ DEVMETHOD(pci_write_config, ata_pci_write_config),
{ 0, 0 }
};
@@ -537,6 +594,8 @@ ata_pcichannel_probe(device_t dev)
{
char buffer[32];
+ if ((intptr_t)device_get_ivars(dev) < 0)
+ return (ENXIO);
sprintf(buffer, "ATA channel %d", (int)(intptr_t)device_get_ivars(dev));
device_set_desc_copy(dev, buffer);
@@ -711,7 +770,7 @@ ata_generic_intr(void *data)
struct ata_channel *ch;
int unit;
- for (unit = 0; unit < ctlr->channels; unit++) {
+ for (unit = 0; unit < ATA_PCI_MAX_CH; unit++) {
if ((ch = ctlr->interrupt[unit].argument))
ctlr->interrupt[unit].function(ch);
}
diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h
index 00c5962..f2a0e13 100644
--- a/sys/dev/ata/ata-pci.h
+++ b/sys/dev/ata/ata-pci.h
@@ -36,6 +36,8 @@ struct ata_chip_id {
char *text;
};
+#define ATA_PCI_MAX_CH 8
+
/* structure describing a PCI ATA controller */
struct ata_pci_controller {
device_t dev;
@@ -65,7 +67,7 @@ struct ata_pci_controller {
struct {
void (*function)(void *);
void *argument;
- } interrupt[8]; /* XXX SOS max ch# for now */
+ } interrupt[ATA_PCI_MAX_CH];
void *chipset_data;
};
@@ -486,6 +488,11 @@ int ata_pci_attach(device_t dev);
int ata_pci_detach(device_t dev);
int ata_pci_suspend(device_t dev);
int ata_pci_resume(device_t dev);
+int ata_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result);
+int ata_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value);
+uint32_t ata_pci_read_config(device_t dev, device_t child, int reg, int width);
+void ata_pci_write_config(device_t dev, device_t child, int reg,
+ uint32_t val, int width);
struct resource * ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags);
int ata_pci_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r);
int ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_filter_t *filter, driver_intr_t *function, void *argument, void **cookiep);
@@ -509,12 +516,6 @@ int ata_mode2idx(int mode);
/* global prototypes from chipsets/ata-*.c */
int ata_ahci_chipinit(device_t);
-int ata_ahci_ch_attach(device_t dev);
-int ata_ahci_ch_detach(device_t dev);
-int ata_ahci_ch_suspend(device_t dev);
-int ata_ahci_ch_resume(device_t dev);
-int ata_ahci_ctlr_reset(device_t dev);
-void ata_ahci_reset(device_t dev);
int ata_marvell_edma_chipinit(device_t);
int ata_sii_chipinit(device_t);
@@ -530,12 +531,16 @@ static device_method_t __CONCAT(dname,_methods)[] = { \
DEVMETHOD(device_suspend, ata_pci_suspend), \
DEVMETHOD(device_resume, ata_pci_resume), \
DEVMETHOD(device_shutdown, bus_generic_shutdown), \
+ DEVMETHOD(bus_read_ivar, ata_pci_read_ivar), \
+ DEVMETHOD(bus_write_ivar, ata_pci_write_ivar), \
DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource), \
DEVMETHOD(bus_release_resource, ata_pci_release_resource), \
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), \
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), \
DEVMETHOD(bus_setup_intr, ata_pci_setup_intr), \
DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr), \
+ DEVMETHOD(pci_read_config, ata_pci_read_config), \
+ DEVMETHOD(pci_write_config, ata_pci_write_config), \
{ 0, 0 } \
}; \
static driver_t __CONCAT(dname,_driver) = { \
diff --git a/sys/dev/ata/chipsets/ata-ahci.c b/sys/dev/ata/chipsets/ata-ahci.c
index 17f78b4..0f76a8d 100644
--- a/sys/dev/ata/chipsets/ata-ahci.c
+++ b/sys/dev/ata/chipsets/ata-ahci.c
@@ -52,6 +52,12 @@ __FBSDID("$FreeBSD$");
#include <ata_if.h>
/* local prototypes */
+static int ata_ahci_ch_attach(device_t dev);
+static int ata_ahci_ch_detach(device_t dev);
+static int ata_ahci_ch_suspend(device_t dev);
+static int ata_ahci_ch_resume(device_t dev);
+static int ata_ahci_ctlr_reset(device_t dev);
+static void ata_ahci_reset(device_t dev);
static int ata_ahci_suspend(device_t dev);
static int ata_ahci_status(device_t dev);
static int ata_ahci_begin_transaction(struct ata_request *request);
@@ -97,6 +103,49 @@ ata_ahci_probe(device_t dev)
return (BUS_PROBE_GENERIC);
}
+static int
+ata_ahci_ata_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if ((intptr_t)device_get_ivars(dev) >= 0)
+ return (ENXIO);
+ device_set_desc_copy(dev, "AHCI SATA controller");
+ ctlr->chipinit = ata_ahci_chipinit;
+ return (BUS_PROBE_GENERIC);
+}
+
+static int
+ata_ahci_ata_attach(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ device_t child;
+ int unit;
+
+ /* do chipset specific setups only needed once */
+ ctlr->legacy = 0;
+ ctlr->ichannels = -1;
+ ctlr->ch_attach = ata_pci_ch_attach;
+ ctlr->ch_detach = ata_pci_ch_detach;
+ ctlr->dev = dev;
+ if (ctlr->chipinit(dev))
+ return ENXIO;
+ /* attach all channels on this controller */
+ for (unit = 0; unit < ctlr->channels; unit++) {
+ if ((ctlr->ichannels & (1 << unit)) == 0)
+ continue;
+ child = device_add_child(dev, "ata",
+ ((unit == 0 || unit == 1) && ctlr->legacy) ?
+ unit : devclass_find_free_unit(ata_devclass, 2));
+ if (child == NULL)
+ device_printf(dev, "failed to add ata child device\n");
+ else
+ device_set_ivars(child, (void *)(intptr_t)unit);
+ }
+ bus_generic_attach(dev);
+ return 0;
+}
+
int
ata_ahci_chipinit(device_t dev)
{
@@ -129,9 +178,15 @@ ata_ahci_chipinit(device_t dev)
/* get the number of HW channels */
ctlr->ichannels = ATA_INL(ctlr->r_res2, ATA_AHCI_PI);
- ctlr->channels =
- MAX(flsl(ctlr->ichannels),
+ ctlr->channels = MAX(flsl(ctlr->ichannels),
(ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_NPMASK) + 1);
+ if (pci_get_devid(dev) == ATA_M88SX6111)
+ ctlr->channels = 1;
+ else if (pci_get_devid(dev) == ATA_M88SX6121)
+ ctlr->channels = 2;
+ else if (pci_get_devid(dev) == ATA_M88SX6141 ||
+ pci_get_devid(dev) == ATA_M88SX6145)
+ ctlr->channels = 4;
ctlr->reset = ata_ahci_reset;
ctlr->ch_attach = ata_ahci_ch_attach;
@@ -183,7 +238,7 @@ ata_ahci_chipinit(device_t dev)
return 0;
}
-int
+static int
ata_ahci_ctlr_reset(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(dev);
@@ -228,7 +283,7 @@ ata_ahci_suspend(device_t dev)
return 0;
}
-int
+static int
ata_ahci_ch_attach(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
@@ -259,7 +314,7 @@ ata_ahci_ch_attach(device_t dev)
return 0;
}
-int
+static int
ata_ahci_ch_detach(device_t dev)
{
@@ -268,7 +323,7 @@ ata_ahci_ch_detach(device_t dev)
return (0);
}
-int
+static int
ata_ahci_ch_suspend(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
@@ -293,7 +348,7 @@ ata_ahci_ch_suspend(device_t dev)
return (0);
}
-int
+static int
ata_ahci_ch_resume(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
@@ -813,7 +868,7 @@ ata_ahci_softreset(device_t dev, int port)
return ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset);
}
-void
+static void
ata_ahci_reset(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
@@ -927,3 +982,26 @@ ata_ahci_setup_fis(struct ata_ahci_cmd_tab *ctp, struct ata_request *request)
}
ATA_DECLARE_DRIVER(ata_ahci);
+static device_method_t ata_ahci_ata_methods[] = {
+ DEVMETHOD(device_probe, ata_ahci_ata_probe),
+ DEVMETHOD(device_attach, ata_ahci_ata_attach),
+ DEVMETHOD(device_detach, ata_pci_detach),
+ DEVMETHOD(device_suspend, ata_pci_suspend),
+ DEVMETHOD(device_resume, ata_pci_resume),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(bus_read_ivar, ata_pci_read_ivar),
+ DEVMETHOD(bus_write_ivar, ata_pci_write_ivar),
+ DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource),
+ DEVMETHOD(bus_release_resource, ata_pci_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_setup_intr, ata_pci_setup_intr),
+ DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr),
+ { 0, 0 }
+};
+static driver_t ata_ahci_ata_driver = {
+ "atapci",
+ ata_ahci_ata_methods,
+ sizeof(struct ata_pci_controller)
+};
+DRIVER_MODULE(ata_ahci_ata, atapci, ata_ahci_ata_driver, ata_pci_devclass, 0, 0);
diff --git a/sys/dev/ata/chipsets/ata-jmicron.c b/sys/dev/ata/chipsets/ata-jmicron.c
index 91108af..2531070 100644
--- a/sys/dev/ata/chipsets/ata-jmicron.c
+++ b/sys/dev/ata/chipsets/ata-jmicron.c
@@ -53,11 +53,6 @@ __FBSDID("$FreeBSD$");
/* local prototypes */
static int ata_jmicron_chipinit(device_t dev);
-static int ata_jmicron_ch_attach(device_t dev);
-static int ata_jmicron_ch_detach(device_t dev);
-static int ata_jmicron_ch_suspend(device_t dev);
-static int ata_jmicron_ch_resume(device_t dev);
-static void ata_jmicron_reset(device_t dev);
static void ata_jmicron_setmode(device_t dev, int mode);
/*
@@ -70,10 +65,10 @@ ata_jmicron_probe(device_t dev)
struct ata_chip_id *idx;
static struct ata_chip_id ids[] =
{{ ATA_JMB360, 0, 1, 0, ATA_SA300, "JMB360" },
- { ATA_JMB361, 0, 1, 1, ATA_SA300, "JMB361" },
- { ATA_JMB363, 0, 2, 1, ATA_SA300, "JMB363" },
- { ATA_JMB365, 0, 1, 2, ATA_SA300, "JMB365" },
- { ATA_JMB366, 0, 2, 2, ATA_SA300, "JMB366" },
+ { ATA_JMB361, 0, 1, 1, ATA_UDMA6, "JMB361" },
+ { ATA_JMB363, 0, 2, 1, ATA_UDMA6, "JMB363" },
+ { ATA_JMB365, 0, 1, 2, ATA_UDMA6, "JMB365" },
+ { ATA_JMB366, 0, 2, 2, ATA_UDMA6, "JMB366" },
{ ATA_JMB368, 0, 0, 1, ATA_UDMA6, "JMB368" },
{ 0, 0, 0, 0, 0, 0}};
char buffer[64];
@@ -101,7 +96,7 @@ static int
ata_jmicron_chipinit(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(dev);
- int error;
+ device_t child;
if (ata_setup_interrupt(dev, ata_generic_intr))
return ENXIO;
@@ -123,116 +118,35 @@ ata_jmicron_chipinit(device_t dev)
/* set controller configuration to a combined setup we support */
pci_write_config(dev, 0x40, 0x80c0a131, 4);
pci_write_config(dev, 0x80, 0x01200000, 4);
-
- if (ctlr->chip->cfg1 && (error = ata_ahci_chipinit(dev)))
- return error;
-
- ctlr->ch_attach = ata_jmicron_ch_attach;
- ctlr->ch_detach = ata_jmicron_ch_detach;
- ctlr->ch_suspend = ata_jmicron_ch_suspend;
- ctlr->ch_resume = ata_jmicron_ch_resume;
- ctlr->reset = ata_jmicron_reset;
+ /* Create AHCI subdevice if AHCI part present. */
+ if (ctlr->chip->cfg1) {
+ child = device_add_child(dev, NULL, -1);
+ if (child != NULL) {
+ device_set_ivars(child, (void *)(intptr_t)-1);
+ bus_generic_attach(dev);
+ }
+ }
+ ctlr->ch_attach = ata_pci_ch_attach;
+ ctlr->ch_detach = ata_pci_ch_detach;
+ ctlr->reset = ata_generic_reset;
ctlr->setmode = ata_jmicron_setmode;
-
- /* set the number of HW channels */
- ctlr->channels = ctlr->chip->cfg1 + ctlr->chip->cfg2;
- ctlr->ichannels |= ((0xffffffffU >> (32 - ctlr->chip->cfg2))
- << ctlr->chip->cfg1);
+ ctlr->channels = ctlr->chip->cfg2;
}
return 0;
}
-static int
-ata_jmicron_ch_attach(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int error;
-
- if (ch->unit >= ctlr->chip->cfg1) {
- ch->unit -= ctlr->chip->cfg1;
- error = ata_pci_ch_attach(dev);
- ch->unit += ctlr->chip->cfg1;
- }
- else
- error = ata_ahci_ch_attach(dev);
- return error;
-}
-
-static int
-ata_jmicron_ch_detach(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int error;
-
- if (ch->unit >= ctlr->chip->cfg1) {
- ch->unit -= ctlr->chip->cfg1;
- error = ata_pci_ch_detach(dev);
- ch->unit += ctlr->chip->cfg1;
- }
- else
- error = ata_ahci_ch_detach(dev);
-
- return (error);
-}
-
-static int
-ata_jmicron_ch_suspend(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int error = 0;
-
- if (ch->unit < ctlr->chip->cfg1)
- error = ata_ahci_ch_suspend(dev);
- return error;
-}
-
-static int
-ata_jmicron_ch_resume(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int error = 0;
-
- if (ch->unit < ctlr->chip->cfg1)
- error = ata_ahci_ch_resume(dev);
- return (error);
-}
-
-static void
-ata_jmicron_reset(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
-
- if (ch->unit >= ctlr->chip->cfg1)
- ata_generic_reset(dev);
- else
- ata_ahci_reset(dev);
-}
-
static void
ata_jmicron_setmode(device_t dev, int mode)
{
- struct ata_pci_controller *ctlr = device_get_softc(GRANDPARENT(dev));
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
-
- if (pci_read_config(dev, 0xdf, 1) & 0x40 || ch->unit >= ctlr->chip->cfg1) {
struct ata_device *atadev = device_get_softc(dev);
/* check for 80pin cable present */
if (pci_read_config(dev, 0x40, 1) & 0x08)
- mode = ata_limit_mode(dev, mode, ATA_UDMA2);
+ mode = ata_limit_mode(dev, mode, ATA_UDMA2);
else
- mode = ata_limit_mode(dev, mode, ATA_UDMA6);
-
+ mode = ata_limit_mode(dev, mode, ATA_UDMA6);
if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
- atadev->mode = mode;
- }
- else
- ata_sata_setmode(dev, mode);
+ atadev->mode = mode;
}
ATA_DECLARE_DRIVER(ata_jmicron);
diff --git a/sys/dev/ata/chipsets/ata-marvell.c b/sys/dev/ata/chipsets/ata-marvell.c
index f08a288..bda1a17 100644
--- a/sys/dev/ata/chipsets/ata-marvell.c
+++ b/sys/dev/ata/chipsets/ata-marvell.c
@@ -54,9 +54,7 @@ __FBSDID("$FreeBSD$");
/* local prototypes */
static int ata_marvell_chipinit(device_t dev);
static int ata_marvell_ch_attach(device_t dev);
-static int ata_marvell_ch_detach(device_t dev);
static void ata_marvell_setmode(device_t dev, int mode);
-static void ata_marvell_reset(device_t dev);
static int ata_marvell_edma_ch_attach(device_t dev);
static int ata_marvell_edma_ch_detach(device_t dev);
static int ata_marvell_edma_status(device_t dev);
@@ -111,10 +109,10 @@ ata_marvell_probe(device_t dev)
{ ATA_M88SX7042, 0, 4, MV_7042, ATA_SA300, "88SX7042" },
{ ATA_M88SX6101, 0, 0, MV_61XX, ATA_UDMA6, "88SX6101" },
{ ATA_M88SX6102, 0, 0, MV_61XX, ATA_UDMA6, "88SX6102" },
- { ATA_M88SX6111, 0, 1, MV_61XX, ATA_SA300, "88SX6111" },
- { ATA_M88SX6121, 0, 2, MV_61XX, ATA_SA300, "88SX6121" },
- { ATA_M88SX6141, 0, 4, MV_61XX, ATA_SA300, "88SX6141" },
- { ATA_M88SX6145, 0, 4, MV_61XX, ATA_SA300, "88SX6145" },
+ { ATA_M88SX6111, 0, 1, MV_61XX, ATA_UDMA6, "88SX6111" },
+ { ATA_M88SX6121, 0, 2, MV_61XX, ATA_UDMA6, "88SX6121" },
+ { ATA_M88SX6141, 0, 4, MV_61XX, ATA_UDMA6, "88SX6141" },
+ { ATA_M88SX6145, 0, 4, MV_61XX, ATA_UDMA6, "88SX6145" },
{ 0, 0, 0, 0, 0, 0}};
if (pci_get_vendor(dev) != ATA_MARVELL_ID)
@@ -142,83 +140,50 @@ ata_marvell_probe(device_t dev)
static int
ata_marvell_chipinit(device_t dev)
{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- int error = 0;
-
- if (ata_setup_interrupt(dev, ata_generic_intr))
- return ENXIO;
-
- if (ctlr->chip->cfg1 && (error = ata_ahci_chipinit(dev)))
- return (error);
- ctlr->ch_attach = ata_marvell_ch_attach;
- ctlr->ch_detach = ata_marvell_ch_detach;
- ctlr->reset = ata_marvell_reset;
- ctlr->setmode = ata_marvell_setmode;
- ctlr->channels = ctlr->chip->cfg1 + 1;
- return (0);
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ device_t child;
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+ /* Create AHCI subdevice if AHCI part present. */
+ if (ctlr->chip->cfg1) {
+ child = device_add_child(dev, NULL, -1);
+ if (child != NULL) {
+ device_set_ivars(child, (void *)(intptr_t)-1);
+ bus_generic_attach(dev);
+ }
+ }
+ ctlr->ch_attach = ata_marvell_ch_attach;
+ ctlr->ch_detach = ata_pci_ch_detach;
+ ctlr->reset = ata_generic_reset;
+ ctlr->setmode = ata_marvell_setmode;
+ ctlr->channels = 1;
+ return (0);
}
static int
ata_marvell_ch_attach(device_t dev)
{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int error;
+ struct ata_channel *ch = device_get_softc(dev);
+ int error;
- if (ch->unit >= ctlr->chip->cfg1) {
- ch->unit -= ctlr->chip->cfg1;
error = ata_pci_ch_attach(dev);
- ch->unit += ctlr->chip->cfg1;
/* dont use 32 bit PIO transfers */
ch->flags |= ATA_USE_16BIT;
- } else
- error = ata_ahci_ch_attach(dev);
- return (error);
-}
-
-static int
-ata_marvell_ch_detach(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int error;
-
- if (ch->unit >= ctlr->chip->cfg1) {
- ch->unit -= ctlr->chip->cfg1;
- error = ata_pci_ch_detach(dev);
- ch->unit += ctlr->chip->cfg1;
- } else
- error = ata_ahci_ch_detach(dev);
- return (error);
-}
-
-static void
-ata_marvell_reset(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
-
- if (ch->unit >= ctlr->chip->cfg1)
- ata_generic_reset(dev);
- else
- ata_ahci_reset(dev);
+ return (error);
}
static void
ata_marvell_setmode(device_t dev, int mode)
{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_device *atadev = device_get_softc(dev);
- if (ch->unit >= ctlr->chip->cfg1) {
mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
mode = ata_check_80pin(dev, mode);
if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
- atadev->mode = mode;
- } else
- ata_sata_setmode(dev, mode);
+ atadev->mode = mode;
}
int
OpenPOWER on IntegriCloud