Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/ata/ahci_platform.c
15109 views
1
/*
2
* AHCI SATA platform driver
3
*
4
* Copyright 2004-2005 Red Hat, Inc.
5
* Jeff Garzik <[email protected]>
6
* Copyright 2010 MontaVista Software, LLC.
7
* Anton Vorontsov <[email protected]>
8
*
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2, or (at your option)
12
* any later version.
13
*/
14
15
#include <linux/kernel.h>
16
#include <linux/gfp.h>
17
#include <linux/module.h>
18
#include <linux/init.h>
19
#include <linux/interrupt.h>
20
#include <linux/device.h>
21
#include <linux/platform_device.h>
22
#include <linux/libata.h>
23
#include <linux/ahci_platform.h>
24
#include "ahci.h"
25
26
static struct scsi_host_template ahci_platform_sht = {
27
AHCI_SHT("ahci_platform"),
28
};
29
30
static int __init ahci_probe(struct platform_device *pdev)
31
{
32
struct device *dev = &pdev->dev;
33
struct ahci_platform_data *pdata = dev->platform_data;
34
struct ata_port_info pi = {
35
.flags = AHCI_FLAG_COMMON,
36
.pio_mask = ATA_PIO4,
37
.udma_mask = ATA_UDMA6,
38
.port_ops = &ahci_ops,
39
};
40
const struct ata_port_info *ppi[] = { &pi, NULL };
41
struct ahci_host_priv *hpriv;
42
struct ata_host *host;
43
struct resource *mem;
44
int irq;
45
int n_ports;
46
int i;
47
int rc;
48
49
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
50
if (!mem) {
51
dev_err(dev, "no mmio space\n");
52
return -EINVAL;
53
}
54
55
irq = platform_get_irq(pdev, 0);
56
if (irq <= 0) {
57
dev_err(dev, "no irq\n");
58
return -EINVAL;
59
}
60
61
if (pdata && pdata->ata_port_info)
62
pi = *pdata->ata_port_info;
63
64
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
65
if (!hpriv) {
66
dev_err(dev, "can't alloc ahci_host_priv\n");
67
return -ENOMEM;
68
}
69
70
hpriv->flags |= (unsigned long)pi.private_data;
71
72
hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
73
if (!hpriv->mmio) {
74
dev_err(dev, "can't map %pR\n", mem);
75
return -ENOMEM;
76
}
77
78
/*
79
* Some platforms might need to prepare for mmio region access,
80
* which could be done in the following init call. So, the mmio
81
* region shouldn't be accessed before init (if provided) has
82
* returned successfully.
83
*/
84
if (pdata && pdata->init) {
85
rc = pdata->init(dev, hpriv->mmio);
86
if (rc)
87
return rc;
88
}
89
90
ahci_save_initial_config(dev, hpriv,
91
pdata ? pdata->force_port_map : 0,
92
pdata ? pdata->mask_port_map : 0);
93
94
/* prepare host */
95
if (hpriv->cap & HOST_CAP_NCQ)
96
pi.flags |= ATA_FLAG_NCQ;
97
98
if (hpriv->cap & HOST_CAP_PMP)
99
pi.flags |= ATA_FLAG_PMP;
100
101
ahci_set_em_messages(hpriv, &pi);
102
103
/* CAP.NP sometimes indicate the index of the last enabled
104
* port, at other times, that of the last possible port, so
105
* determining the maximum port number requires looking at
106
* both CAP.NP and port_map.
107
*/
108
n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
109
110
host = ata_host_alloc_pinfo(dev, ppi, n_ports);
111
if (!host) {
112
rc = -ENOMEM;
113
goto err0;
114
}
115
116
host->private_data = hpriv;
117
118
if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
119
host->flags |= ATA_HOST_PARALLEL_SCAN;
120
else
121
printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n");
122
123
if (pi.flags & ATA_FLAG_EM)
124
ahci_reset_em(host);
125
126
for (i = 0; i < host->n_ports; i++) {
127
struct ata_port *ap = host->ports[i];
128
129
ata_port_desc(ap, "mmio %pR", mem);
130
ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
131
132
/* set enclosure management message type */
133
if (ap->flags & ATA_FLAG_EM)
134
ap->em_message_type = hpriv->em_msg_type;
135
136
/* disabled/not-implemented port */
137
if (!(hpriv->port_map & (1 << i)))
138
ap->ops = &ata_dummy_port_ops;
139
}
140
141
rc = ahci_reset_controller(host);
142
if (rc)
143
goto err0;
144
145
ahci_init_controller(host);
146
ahci_print_info(host, "platform");
147
148
rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
149
&ahci_platform_sht);
150
if (rc)
151
goto err0;
152
153
return 0;
154
err0:
155
if (pdata && pdata->exit)
156
pdata->exit(dev);
157
return rc;
158
}
159
160
static int __devexit ahci_remove(struct platform_device *pdev)
161
{
162
struct device *dev = &pdev->dev;
163
struct ahci_platform_data *pdata = dev->platform_data;
164
struct ata_host *host = dev_get_drvdata(dev);
165
166
ata_host_detach(host);
167
168
if (pdata && pdata->exit)
169
pdata->exit(dev);
170
171
return 0;
172
}
173
174
static struct platform_driver ahci_driver = {
175
.remove = __devexit_p(ahci_remove),
176
.driver = {
177
.name = "ahci",
178
.owner = THIS_MODULE,
179
},
180
};
181
182
static int __init ahci_init(void)
183
{
184
return platform_driver_probe(&ahci_driver, ahci_probe);
185
}
186
module_init(ahci_init);
187
188
static void __exit ahci_exit(void)
189
{
190
platform_driver_unregister(&ahci_driver);
191
}
192
module_exit(ahci_exit);
193
194
MODULE_DESCRIPTION("AHCI SATA platform driver");
195
MODULE_AUTHOR("Anton Vorontsov <[email protected]>");
196
MODULE_LICENSE("GPL");
197
MODULE_ALIAS("platform:ahci");
198
199