Commit | Line | Data |
---|---|---|
658d439b TI |
1 | /* |
2 | * FUJITSU Extended Socket Network Device driver | |
3 | * Copyright (c) 2015 FUJITSU LIMITED | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms and conditions of the GNU General Public License, | |
7 | * version 2, as published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
12 | * more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License along with | |
15 | * this program; if not, see <http://www.gnu.org/licenses/>. | |
16 | * | |
17 | * The full GNU General Public License is included in this distribution in | |
18 | * the file called "COPYING". | |
19 | * | |
20 | */ | |
21 | ||
22 | #include <linux/module.h> | |
23 | #include <linux/types.h> | |
24 | #include <linux/nls.h> | |
25 | #include <linux/platform_device.h> | |
2fcbca68 | 26 | #include <linux/netdevice.h> |
658d439b TI |
27 | |
28 | #include "fjes.h" | |
29 | ||
30 | #define MAJ 1 | |
31 | #define MIN 0 | |
32 | #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) | |
33 | #define DRV_NAME "fjes" | |
34 | char fjes_driver_name[] = DRV_NAME; | |
35 | char fjes_driver_version[] = DRV_VERSION; | |
36 | static const char fjes_driver_string[] = | |
37 | "FUJITSU Extended Socket Network Device Driver"; | |
38 | static const char fjes_copyright[] = | |
39 | "Copyright (c) 2015 FUJITSU LIMITED"; | |
40 | ||
41 | MODULE_AUTHOR("Taku Izumi <izumi.taku@jp.fujitsu.com>"); | |
42 | MODULE_DESCRIPTION("FUJITSU Extended Socket Network Device Driver"); | |
43 | MODULE_LICENSE("GPL"); | |
44 | MODULE_VERSION(DRV_VERSION); | |
45 | ||
46 | static int fjes_acpi_add(struct acpi_device *); | |
47 | static int fjes_acpi_remove(struct acpi_device *); | |
48 | static acpi_status fjes_get_acpi_resource(struct acpi_resource *, void*); | |
49 | ||
50 | static int fjes_probe(struct platform_device *); | |
51 | static int fjes_remove(struct platform_device *); | |
52 | ||
2fcbca68 TI |
53 | static int fjes_sw_init(struct fjes_adapter *); |
54 | static void fjes_netdev_setup(struct net_device *); | |
55 | ||
658d439b TI |
56 | static const struct acpi_device_id fjes_acpi_ids[] = { |
57 | {"PNP0C02", 0}, | |
58 | {"", 0}, | |
59 | }; | |
60 | MODULE_DEVICE_TABLE(acpi, fjes_acpi_ids); | |
61 | ||
62 | static struct acpi_driver fjes_acpi_driver = { | |
63 | .name = DRV_NAME, | |
64 | .class = DRV_NAME, | |
65 | .owner = THIS_MODULE, | |
66 | .ids = fjes_acpi_ids, | |
67 | .ops = { | |
68 | .add = fjes_acpi_add, | |
69 | .remove = fjes_acpi_remove, | |
70 | }, | |
71 | }; | |
72 | ||
73 | static struct platform_driver fjes_driver = { | |
74 | .driver = { | |
75 | .name = DRV_NAME, | |
76 | .owner = THIS_MODULE, | |
77 | }, | |
78 | .probe = fjes_probe, | |
79 | .remove = fjes_remove, | |
80 | }; | |
81 | ||
82 | static struct resource fjes_resource[] = { | |
83 | { | |
84 | .flags = IORESOURCE_MEM, | |
85 | .start = 0, | |
86 | .end = 0, | |
87 | }, | |
88 | { | |
89 | .flags = IORESOURCE_IRQ, | |
90 | .start = 0, | |
91 | .end = 0, | |
92 | }, | |
93 | }; | |
94 | ||
95 | static int fjes_acpi_add(struct acpi_device *device) | |
96 | { | |
97 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; | |
98 | char str_buf[sizeof(FJES_ACPI_SYMBOL) + 1]; | |
99 | struct platform_device *plat_dev; | |
100 | union acpi_object *str; | |
101 | acpi_status status; | |
102 | int result; | |
103 | ||
104 | status = acpi_evaluate_object(device->handle, "_STR", NULL, &buffer); | |
105 | if (ACPI_FAILURE(status)) | |
106 | return -ENODEV; | |
107 | ||
108 | str = buffer.pointer; | |
109 | result = utf16s_to_utf8s((wchar_t *)str->string.pointer, | |
110 | str->string.length, UTF16_LITTLE_ENDIAN, | |
111 | str_buf, sizeof(str_buf) - 1); | |
112 | str_buf[result] = 0; | |
113 | ||
114 | if (strncmp(FJES_ACPI_SYMBOL, str_buf, strlen(FJES_ACPI_SYMBOL)) != 0) { | |
115 | kfree(buffer.pointer); | |
116 | return -ENODEV; | |
117 | } | |
118 | kfree(buffer.pointer); | |
119 | ||
120 | status = acpi_walk_resources(device->handle, METHOD_NAME__CRS, | |
121 | fjes_get_acpi_resource, fjes_resource); | |
122 | if (ACPI_FAILURE(status)) | |
123 | return -ENODEV; | |
124 | ||
125 | /* create platform_device */ | |
126 | plat_dev = platform_device_register_simple(DRV_NAME, 0, fjes_resource, | |
127 | ARRAY_SIZE(fjes_resource)); | |
128 | device->driver_data = plat_dev; | |
129 | ||
130 | return 0; | |
131 | } | |
132 | ||
133 | static int fjes_acpi_remove(struct acpi_device *device) | |
134 | { | |
135 | struct platform_device *plat_dev; | |
136 | ||
137 | plat_dev = (struct platform_device *)acpi_driver_data(device); | |
138 | platform_device_unregister(plat_dev); | |
139 | ||
140 | return 0; | |
141 | } | |
142 | ||
143 | static acpi_status | |
144 | fjes_get_acpi_resource(struct acpi_resource *acpi_res, void *data) | |
145 | { | |
146 | struct acpi_resource_address32 *addr; | |
147 | struct acpi_resource_irq *irq; | |
148 | struct resource *res = data; | |
149 | ||
150 | switch (acpi_res->type) { | |
151 | case ACPI_RESOURCE_TYPE_ADDRESS32: | |
152 | addr = &acpi_res->data.address32; | |
153 | res[0].start = addr->address.minimum; | |
154 | res[0].end = addr->address.minimum + | |
155 | addr->address.address_length - 1; | |
156 | break; | |
157 | ||
158 | case ACPI_RESOURCE_TYPE_IRQ: | |
159 | irq = &acpi_res->data.irq; | |
160 | if (irq->interrupt_count != 1) | |
161 | return AE_ERROR; | |
162 | res[1].start = irq->interrupts[0]; | |
163 | res[1].end = irq->interrupts[0]; | |
164 | break; | |
165 | ||
166 | default: | |
167 | break; | |
168 | } | |
169 | ||
170 | return AE_OK; | |
171 | } | |
172 | ||
2fcbca68 TI |
173 | static const struct net_device_ops fjes_netdev_ops = { |
174 | }; | |
175 | ||
658d439b TI |
176 | /* fjes_probe - Device Initialization Routine */ |
177 | static int fjes_probe(struct platform_device *plat_dev) | |
178 | { | |
2fcbca68 TI |
179 | struct fjes_adapter *adapter; |
180 | struct net_device *netdev; | |
181 | struct resource *res; | |
182 | struct fjes_hw *hw; | |
183 | int err; | |
184 | ||
185 | err = -ENOMEM; | |
186 | netdev = alloc_netdev_mq(sizeof(struct fjes_adapter), "es%d", | |
187 | NET_NAME_UNKNOWN, fjes_netdev_setup, | |
188 | FJES_MAX_QUEUES); | |
189 | ||
190 | if (!netdev) | |
191 | goto err_out; | |
192 | ||
193 | SET_NETDEV_DEV(netdev, &plat_dev->dev); | |
194 | ||
195 | dev_set_drvdata(&plat_dev->dev, netdev); | |
196 | adapter = netdev_priv(netdev); | |
197 | adapter->netdev = netdev; | |
198 | adapter->plat_dev = plat_dev; | |
199 | hw = &adapter->hw; | |
200 | hw->back = adapter; | |
201 | ||
202 | /* setup the private structure */ | |
203 | err = fjes_sw_init(adapter); | |
204 | if (err) | |
205 | goto err_free_netdev; | |
206 | ||
207 | adapter->force_reset = false; | |
208 | adapter->open_guard = false; | |
209 | ||
210 | res = platform_get_resource(plat_dev, IORESOURCE_MEM, 0); | |
211 | hw->hw_res.start = res->start; | |
212 | hw->hw_res.size = res->end - res->start + 1; | |
213 | hw->hw_res.irq = platform_get_irq(plat_dev, 0); | |
214 | err = fjes_hw_init(&adapter->hw); | |
215 | if (err) | |
216 | goto err_free_netdev; | |
217 | ||
218 | /* setup MAC address (02:00:00:00:00:[epid])*/ | |
219 | netdev->dev_addr[0] = 2; | |
220 | netdev->dev_addr[1] = 0; | |
221 | netdev->dev_addr[2] = 0; | |
222 | netdev->dev_addr[3] = 0; | |
223 | netdev->dev_addr[4] = 0; | |
224 | netdev->dev_addr[5] = hw->my_epid; /* EPID */ | |
225 | ||
226 | err = register_netdev(netdev); | |
227 | if (err) | |
228 | goto err_hw_exit; | |
229 | ||
230 | netif_carrier_off(netdev); | |
231 | ||
658d439b | 232 | return 0; |
2fcbca68 TI |
233 | |
234 | err_hw_exit: | |
235 | fjes_hw_exit(&adapter->hw); | |
236 | err_free_netdev: | |
237 | free_netdev(netdev); | |
238 | err_out: | |
239 | return err; | |
658d439b TI |
240 | } |
241 | ||
242 | /* fjes_remove - Device Removal Routine */ | |
243 | static int fjes_remove(struct platform_device *plat_dev) | |
244 | { | |
2fcbca68 TI |
245 | struct net_device *netdev = dev_get_drvdata(&plat_dev->dev); |
246 | struct fjes_adapter *adapter = netdev_priv(netdev); | |
247 | struct fjes_hw *hw = &adapter->hw; | |
248 | ||
249 | unregister_netdev(netdev); | |
250 | ||
251 | fjes_hw_exit(hw); | |
252 | ||
253 | free_netdev(netdev); | |
254 | ||
658d439b TI |
255 | return 0; |
256 | } | |
257 | ||
2fcbca68 TI |
258 | static int fjes_sw_init(struct fjes_adapter *adapter) |
259 | { | |
260 | return 0; | |
261 | } | |
262 | ||
263 | /* fjes_netdev_setup - netdevice initialization routine */ | |
264 | static void fjes_netdev_setup(struct net_device *netdev) | |
265 | { | |
266 | ether_setup(netdev); | |
267 | ||
268 | netdev->watchdog_timeo = FJES_TX_RETRY_INTERVAL; | |
269 | netdev->netdev_ops = &fjes_netdev_ops; | |
270 | netdev->mtu = fjes_support_mtu[0]; | |
271 | netdev->flags |= IFF_BROADCAST; | |
272 | netdev->features |= NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_CTAG_FILTER; | |
273 | } | |
274 | ||
658d439b TI |
275 | /* fjes_init_module - Driver Registration Routine */ |
276 | static int __init fjes_init_module(void) | |
277 | { | |
278 | int result; | |
279 | ||
280 | pr_info("%s - version %s - %s\n", | |
281 | fjes_driver_string, fjes_driver_version, fjes_copyright); | |
282 | ||
283 | result = platform_driver_register(&fjes_driver); | |
284 | if (result < 0) | |
285 | return result; | |
286 | ||
287 | result = acpi_bus_register_driver(&fjes_acpi_driver); | |
288 | if (result < 0) | |
289 | goto fail_acpi_driver; | |
290 | ||
291 | return 0; | |
292 | ||
293 | fail_acpi_driver: | |
294 | platform_driver_unregister(&fjes_driver); | |
295 | return result; | |
296 | } | |
297 | ||
298 | module_init(fjes_init_module); | |
299 | ||
300 | /* fjes_exit_module - Driver Exit Cleanup Routine */ | |
301 | static void __exit fjes_exit_module(void) | |
302 | { | |
303 | acpi_bus_unregister_driver(&fjes_acpi_driver); | |
304 | platform_driver_unregister(&fjes_driver); | |
305 | } | |
306 | ||
307 | module_exit(fjes_exit_module); |