xref: /openbmc/linux/drivers/net/fjes/fjes_main.c (revision 2fcbca687702163ae3a37ec4eac5905d6f119296)
1658d439bSTaku Izumi /*
2658d439bSTaku Izumi  *  FUJITSU Extended Socket Network Device driver
3658d439bSTaku Izumi  *  Copyright (c) 2015 FUJITSU LIMITED
4658d439bSTaku Izumi  *
5658d439bSTaku Izumi  * This program is free software; you can redistribute it and/or modify it
6658d439bSTaku Izumi  * under the terms and conditions of the GNU General Public License,
7658d439bSTaku Izumi  * version 2, as published by the Free Software Foundation.
8658d439bSTaku Izumi  *
9658d439bSTaku Izumi  * This program is distributed in the hope it will be useful, but WITHOUT
10658d439bSTaku Izumi  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11658d439bSTaku Izumi  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12658d439bSTaku Izumi  * more details.
13658d439bSTaku Izumi  *
14658d439bSTaku Izumi  * You should have received a copy of the GNU General Public License along with
15658d439bSTaku Izumi  * this program; if not, see <http://www.gnu.org/licenses/>.
16658d439bSTaku Izumi  *
17658d439bSTaku Izumi  * The full GNU General Public License is included in this distribution in
18658d439bSTaku Izumi  * the file called "COPYING".
19658d439bSTaku Izumi  *
20658d439bSTaku Izumi  */
21658d439bSTaku Izumi 
22658d439bSTaku Izumi #include <linux/module.h>
23658d439bSTaku Izumi #include <linux/types.h>
24658d439bSTaku Izumi #include <linux/nls.h>
25658d439bSTaku Izumi #include <linux/platform_device.h>
26*2fcbca68STaku Izumi #include <linux/netdevice.h>
27658d439bSTaku Izumi 
28658d439bSTaku Izumi #include "fjes.h"
29658d439bSTaku Izumi 
30658d439bSTaku Izumi #define MAJ 1
31658d439bSTaku Izumi #define MIN 0
32658d439bSTaku Izumi #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN)
33658d439bSTaku Izumi #define DRV_NAME	"fjes"
34658d439bSTaku Izumi char fjes_driver_name[] = DRV_NAME;
35658d439bSTaku Izumi char fjes_driver_version[] = DRV_VERSION;
36658d439bSTaku Izumi static const char fjes_driver_string[] =
37658d439bSTaku Izumi 		"FUJITSU Extended Socket Network Device Driver";
38658d439bSTaku Izumi static const char fjes_copyright[] =
39658d439bSTaku Izumi 		"Copyright (c) 2015 FUJITSU LIMITED";
40658d439bSTaku Izumi 
41658d439bSTaku Izumi MODULE_AUTHOR("Taku Izumi <izumi.taku@jp.fujitsu.com>");
42658d439bSTaku Izumi MODULE_DESCRIPTION("FUJITSU Extended Socket Network Device Driver");
43658d439bSTaku Izumi MODULE_LICENSE("GPL");
44658d439bSTaku Izumi MODULE_VERSION(DRV_VERSION);
45658d439bSTaku Izumi 
46658d439bSTaku Izumi static int fjes_acpi_add(struct acpi_device *);
47658d439bSTaku Izumi static int fjes_acpi_remove(struct acpi_device *);
48658d439bSTaku Izumi static acpi_status fjes_get_acpi_resource(struct acpi_resource *, void*);
49658d439bSTaku Izumi 
50658d439bSTaku Izumi static int fjes_probe(struct platform_device *);
51658d439bSTaku Izumi static int fjes_remove(struct platform_device *);
52658d439bSTaku Izumi 
53*2fcbca68STaku Izumi static int fjes_sw_init(struct fjes_adapter *);
54*2fcbca68STaku Izumi static void fjes_netdev_setup(struct net_device *);
55*2fcbca68STaku Izumi 
56658d439bSTaku Izumi static const struct acpi_device_id fjes_acpi_ids[] = {
57658d439bSTaku Izumi 	{"PNP0C02", 0},
58658d439bSTaku Izumi 	{"", 0},
59658d439bSTaku Izumi };
60658d439bSTaku Izumi MODULE_DEVICE_TABLE(acpi, fjes_acpi_ids);
61658d439bSTaku Izumi 
62658d439bSTaku Izumi static struct acpi_driver fjes_acpi_driver = {
63658d439bSTaku Izumi 	.name = DRV_NAME,
64658d439bSTaku Izumi 	.class = DRV_NAME,
65658d439bSTaku Izumi 	.owner = THIS_MODULE,
66658d439bSTaku Izumi 	.ids = fjes_acpi_ids,
67658d439bSTaku Izumi 	.ops = {
68658d439bSTaku Izumi 		.add = fjes_acpi_add,
69658d439bSTaku Izumi 		.remove = fjes_acpi_remove,
70658d439bSTaku Izumi 	},
71658d439bSTaku Izumi };
72658d439bSTaku Izumi 
73658d439bSTaku Izumi static struct platform_driver fjes_driver = {
74658d439bSTaku Izumi 	.driver = {
75658d439bSTaku Izumi 		.name = DRV_NAME,
76658d439bSTaku Izumi 		.owner = THIS_MODULE,
77658d439bSTaku Izumi 	},
78658d439bSTaku Izumi 	.probe = fjes_probe,
79658d439bSTaku Izumi 	.remove = fjes_remove,
80658d439bSTaku Izumi };
81658d439bSTaku Izumi 
82658d439bSTaku Izumi static struct resource fjes_resource[] = {
83658d439bSTaku Izumi 	{
84658d439bSTaku Izumi 		.flags = IORESOURCE_MEM,
85658d439bSTaku Izumi 		.start = 0,
86658d439bSTaku Izumi 		.end = 0,
87658d439bSTaku Izumi 	},
88658d439bSTaku Izumi 	{
89658d439bSTaku Izumi 		.flags = IORESOURCE_IRQ,
90658d439bSTaku Izumi 		.start = 0,
91658d439bSTaku Izumi 		.end = 0,
92658d439bSTaku Izumi 	},
93658d439bSTaku Izumi };
94658d439bSTaku Izumi 
95658d439bSTaku Izumi static int fjes_acpi_add(struct acpi_device *device)
96658d439bSTaku Izumi {
97658d439bSTaku Izumi 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
98658d439bSTaku Izumi 	char str_buf[sizeof(FJES_ACPI_SYMBOL) + 1];
99658d439bSTaku Izumi 	struct platform_device *plat_dev;
100658d439bSTaku Izumi 	union acpi_object *str;
101658d439bSTaku Izumi 	acpi_status status;
102658d439bSTaku Izumi 	int result;
103658d439bSTaku Izumi 
104658d439bSTaku Izumi 	status = acpi_evaluate_object(device->handle, "_STR", NULL, &buffer);
105658d439bSTaku Izumi 	if (ACPI_FAILURE(status))
106658d439bSTaku Izumi 		return -ENODEV;
107658d439bSTaku Izumi 
108658d439bSTaku Izumi 	str = buffer.pointer;
109658d439bSTaku Izumi 	result = utf16s_to_utf8s((wchar_t *)str->string.pointer,
110658d439bSTaku Izumi 				 str->string.length, UTF16_LITTLE_ENDIAN,
111658d439bSTaku Izumi 				 str_buf, sizeof(str_buf) - 1);
112658d439bSTaku Izumi 	str_buf[result] = 0;
113658d439bSTaku Izumi 
114658d439bSTaku Izumi 	if (strncmp(FJES_ACPI_SYMBOL, str_buf, strlen(FJES_ACPI_SYMBOL)) != 0) {
115658d439bSTaku Izumi 		kfree(buffer.pointer);
116658d439bSTaku Izumi 		return -ENODEV;
117658d439bSTaku Izumi 	}
118658d439bSTaku Izumi 	kfree(buffer.pointer);
119658d439bSTaku Izumi 
120658d439bSTaku Izumi 	status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
121658d439bSTaku Izumi 				     fjes_get_acpi_resource, fjes_resource);
122658d439bSTaku Izumi 	if (ACPI_FAILURE(status))
123658d439bSTaku Izumi 		return -ENODEV;
124658d439bSTaku Izumi 
125658d439bSTaku Izumi 	/* create platform_device */
126658d439bSTaku Izumi 	plat_dev = platform_device_register_simple(DRV_NAME, 0, fjes_resource,
127658d439bSTaku Izumi 						   ARRAY_SIZE(fjes_resource));
128658d439bSTaku Izumi 	device->driver_data = plat_dev;
129658d439bSTaku Izumi 
130658d439bSTaku Izumi 	return 0;
131658d439bSTaku Izumi }
132658d439bSTaku Izumi 
133658d439bSTaku Izumi static int fjes_acpi_remove(struct acpi_device *device)
134658d439bSTaku Izumi {
135658d439bSTaku Izumi 	struct platform_device *plat_dev;
136658d439bSTaku Izumi 
137658d439bSTaku Izumi 	plat_dev = (struct platform_device *)acpi_driver_data(device);
138658d439bSTaku Izumi 	platform_device_unregister(plat_dev);
139658d439bSTaku Izumi 
140658d439bSTaku Izumi 	return 0;
141658d439bSTaku Izumi }
142658d439bSTaku Izumi 
143658d439bSTaku Izumi static acpi_status
144658d439bSTaku Izumi fjes_get_acpi_resource(struct acpi_resource *acpi_res, void *data)
145658d439bSTaku Izumi {
146658d439bSTaku Izumi 	struct acpi_resource_address32 *addr;
147658d439bSTaku Izumi 	struct acpi_resource_irq *irq;
148658d439bSTaku Izumi 	struct resource *res = data;
149658d439bSTaku Izumi 
150658d439bSTaku Izumi 	switch (acpi_res->type) {
151658d439bSTaku Izumi 	case ACPI_RESOURCE_TYPE_ADDRESS32:
152658d439bSTaku Izumi 		addr = &acpi_res->data.address32;
153658d439bSTaku Izumi 		res[0].start = addr->address.minimum;
154658d439bSTaku Izumi 		res[0].end = addr->address.minimum +
155658d439bSTaku Izumi 			addr->address.address_length - 1;
156658d439bSTaku Izumi 		break;
157658d439bSTaku Izumi 
158658d439bSTaku Izumi 	case ACPI_RESOURCE_TYPE_IRQ:
159658d439bSTaku Izumi 		irq = &acpi_res->data.irq;
160658d439bSTaku Izumi 		if (irq->interrupt_count != 1)
161658d439bSTaku Izumi 			return AE_ERROR;
162658d439bSTaku Izumi 		res[1].start = irq->interrupts[0];
163658d439bSTaku Izumi 		res[1].end = irq->interrupts[0];
164658d439bSTaku Izumi 		break;
165658d439bSTaku Izumi 
166658d439bSTaku Izumi 	default:
167658d439bSTaku Izumi 		break;
168658d439bSTaku Izumi 	}
169658d439bSTaku Izumi 
170658d439bSTaku Izumi 	return AE_OK;
171658d439bSTaku Izumi }
172658d439bSTaku Izumi 
173*2fcbca68STaku Izumi static const struct net_device_ops fjes_netdev_ops = {
174*2fcbca68STaku Izumi };
175*2fcbca68STaku Izumi 
176658d439bSTaku Izumi /* fjes_probe - Device Initialization Routine */
177658d439bSTaku Izumi static int fjes_probe(struct platform_device *plat_dev)
178658d439bSTaku Izumi {
179*2fcbca68STaku Izumi 	struct fjes_adapter *adapter;
180*2fcbca68STaku Izumi 	struct net_device *netdev;
181*2fcbca68STaku Izumi 	struct resource *res;
182*2fcbca68STaku Izumi 	struct fjes_hw *hw;
183*2fcbca68STaku Izumi 	int err;
184*2fcbca68STaku Izumi 
185*2fcbca68STaku Izumi 	err = -ENOMEM;
186*2fcbca68STaku Izumi 	netdev = alloc_netdev_mq(sizeof(struct fjes_adapter), "es%d",
187*2fcbca68STaku Izumi 				 NET_NAME_UNKNOWN, fjes_netdev_setup,
188*2fcbca68STaku Izumi 				 FJES_MAX_QUEUES);
189*2fcbca68STaku Izumi 
190*2fcbca68STaku Izumi 	if (!netdev)
191*2fcbca68STaku Izumi 		goto err_out;
192*2fcbca68STaku Izumi 
193*2fcbca68STaku Izumi 	SET_NETDEV_DEV(netdev, &plat_dev->dev);
194*2fcbca68STaku Izumi 
195*2fcbca68STaku Izumi 	dev_set_drvdata(&plat_dev->dev, netdev);
196*2fcbca68STaku Izumi 	adapter = netdev_priv(netdev);
197*2fcbca68STaku Izumi 	adapter->netdev = netdev;
198*2fcbca68STaku Izumi 	adapter->plat_dev = plat_dev;
199*2fcbca68STaku Izumi 	hw = &adapter->hw;
200*2fcbca68STaku Izumi 	hw->back = adapter;
201*2fcbca68STaku Izumi 
202*2fcbca68STaku Izumi 	/* setup the private structure */
203*2fcbca68STaku Izumi 	err = fjes_sw_init(adapter);
204*2fcbca68STaku Izumi 	if (err)
205*2fcbca68STaku Izumi 		goto err_free_netdev;
206*2fcbca68STaku Izumi 
207*2fcbca68STaku Izumi 	adapter->force_reset = false;
208*2fcbca68STaku Izumi 	adapter->open_guard = false;
209*2fcbca68STaku Izumi 
210*2fcbca68STaku Izumi 	res = platform_get_resource(plat_dev, IORESOURCE_MEM, 0);
211*2fcbca68STaku Izumi 	hw->hw_res.start = res->start;
212*2fcbca68STaku Izumi 	hw->hw_res.size = res->end - res->start + 1;
213*2fcbca68STaku Izumi 	hw->hw_res.irq = platform_get_irq(plat_dev, 0);
214*2fcbca68STaku Izumi 	err = fjes_hw_init(&adapter->hw);
215*2fcbca68STaku Izumi 	if (err)
216*2fcbca68STaku Izumi 		goto err_free_netdev;
217*2fcbca68STaku Izumi 
218*2fcbca68STaku Izumi 	/* setup MAC address (02:00:00:00:00:[epid])*/
219*2fcbca68STaku Izumi 	netdev->dev_addr[0] = 2;
220*2fcbca68STaku Izumi 	netdev->dev_addr[1] = 0;
221*2fcbca68STaku Izumi 	netdev->dev_addr[2] = 0;
222*2fcbca68STaku Izumi 	netdev->dev_addr[3] = 0;
223*2fcbca68STaku Izumi 	netdev->dev_addr[4] = 0;
224*2fcbca68STaku Izumi 	netdev->dev_addr[5] = hw->my_epid; /* EPID */
225*2fcbca68STaku Izumi 
226*2fcbca68STaku Izumi 	err = register_netdev(netdev);
227*2fcbca68STaku Izumi 	if (err)
228*2fcbca68STaku Izumi 		goto err_hw_exit;
229*2fcbca68STaku Izumi 
230*2fcbca68STaku Izumi 	netif_carrier_off(netdev);
231*2fcbca68STaku Izumi 
232658d439bSTaku Izumi 	return 0;
233*2fcbca68STaku Izumi 
234*2fcbca68STaku Izumi err_hw_exit:
235*2fcbca68STaku Izumi 	fjes_hw_exit(&adapter->hw);
236*2fcbca68STaku Izumi err_free_netdev:
237*2fcbca68STaku Izumi 	free_netdev(netdev);
238*2fcbca68STaku Izumi err_out:
239*2fcbca68STaku Izumi 	return err;
240658d439bSTaku Izumi }
241658d439bSTaku Izumi 
242658d439bSTaku Izumi /* fjes_remove - Device Removal Routine */
243658d439bSTaku Izumi static int fjes_remove(struct platform_device *plat_dev)
244658d439bSTaku Izumi {
245*2fcbca68STaku Izumi 	struct net_device *netdev = dev_get_drvdata(&plat_dev->dev);
246*2fcbca68STaku Izumi 	struct fjes_adapter *adapter = netdev_priv(netdev);
247*2fcbca68STaku Izumi 	struct fjes_hw *hw = &adapter->hw;
248*2fcbca68STaku Izumi 
249*2fcbca68STaku Izumi 	unregister_netdev(netdev);
250*2fcbca68STaku Izumi 
251*2fcbca68STaku Izumi 	fjes_hw_exit(hw);
252*2fcbca68STaku Izumi 
253*2fcbca68STaku Izumi 	free_netdev(netdev);
254*2fcbca68STaku Izumi 
255658d439bSTaku Izumi 	return 0;
256658d439bSTaku Izumi }
257658d439bSTaku Izumi 
258*2fcbca68STaku Izumi static int fjes_sw_init(struct fjes_adapter *adapter)
259*2fcbca68STaku Izumi {
260*2fcbca68STaku Izumi 	return 0;
261*2fcbca68STaku Izumi }
262*2fcbca68STaku Izumi 
263*2fcbca68STaku Izumi /* fjes_netdev_setup - netdevice initialization routine */
264*2fcbca68STaku Izumi static void fjes_netdev_setup(struct net_device *netdev)
265*2fcbca68STaku Izumi {
266*2fcbca68STaku Izumi 	ether_setup(netdev);
267*2fcbca68STaku Izumi 
268*2fcbca68STaku Izumi 	netdev->watchdog_timeo = FJES_TX_RETRY_INTERVAL;
269*2fcbca68STaku Izumi 	netdev->netdev_ops = &fjes_netdev_ops;
270*2fcbca68STaku Izumi 	netdev->mtu = fjes_support_mtu[0];
271*2fcbca68STaku Izumi 	netdev->flags |= IFF_BROADCAST;
272*2fcbca68STaku Izumi 	netdev->features |= NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_CTAG_FILTER;
273*2fcbca68STaku Izumi }
274*2fcbca68STaku Izumi 
275658d439bSTaku Izumi /* fjes_init_module - Driver Registration Routine */
276658d439bSTaku Izumi static int __init fjes_init_module(void)
277658d439bSTaku Izumi {
278658d439bSTaku Izumi 	int result;
279658d439bSTaku Izumi 
280658d439bSTaku Izumi 	pr_info("%s - version %s - %s\n",
281658d439bSTaku Izumi 		fjes_driver_string, fjes_driver_version, fjes_copyright);
282658d439bSTaku Izumi 
283658d439bSTaku Izumi 	result = platform_driver_register(&fjes_driver);
284658d439bSTaku Izumi 	if (result < 0)
285658d439bSTaku Izumi 		return result;
286658d439bSTaku Izumi 
287658d439bSTaku Izumi 	result = acpi_bus_register_driver(&fjes_acpi_driver);
288658d439bSTaku Izumi 	if (result < 0)
289658d439bSTaku Izumi 		goto fail_acpi_driver;
290658d439bSTaku Izumi 
291658d439bSTaku Izumi 	return 0;
292658d439bSTaku Izumi 
293658d439bSTaku Izumi fail_acpi_driver:
294658d439bSTaku Izumi 	platform_driver_unregister(&fjes_driver);
295658d439bSTaku Izumi 	return result;
296658d439bSTaku Izumi }
297658d439bSTaku Izumi 
298658d439bSTaku Izumi module_init(fjes_init_module);
299658d439bSTaku Izumi 
300658d439bSTaku Izumi /* fjes_exit_module - Driver Exit Cleanup Routine */
301658d439bSTaku Izumi static void __exit fjes_exit_module(void)
302658d439bSTaku Izumi {
303658d439bSTaku Izumi 	acpi_bus_unregister_driver(&fjes_acpi_driver);
304658d439bSTaku Izumi 	platform_driver_unregister(&fjes_driver);
305658d439bSTaku Izumi }
306658d439bSTaku Izumi 
307658d439bSTaku Izumi module_exit(fjes_exit_module);
308