diff options
author | Jan-Bernd Themann <ossthema@de.ibm.com> | 2007-02-28 12:34:02 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-04-28 11:00:56 -0400 |
commit | 1acf2318dd136edfbfa30f1f33b43f69f2e2ec6c (patch) | |
tree | 2d79a977fc773f43e6f8be76f5fdaf0b8c251226 /drivers/net/ehea | |
parent | 459e536b1ddfd217ec8a3437a3214968a98223c7 (diff) |
ehea: dynamic add / remove port
This patch introduces functionality to dynamically add / remove
ehea ports via an userspace DLPAR tool. It creates a subnode for
each logical port in the sysfs.
Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/ehea')
-rw-r--r-- | drivers/net/ehea/ehea.h | 9 | ||||
-rw-r--r-- | drivers/net/ehea/ehea_main.c | 439 |
2 files changed, 323 insertions, 125 deletions
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 42295d61ecd8..e595d6b38e7c 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h | |||
@@ -39,7 +39,7 @@ | |||
39 | #include <asm/io.h> | 39 | #include <asm/io.h> |
40 | 40 | ||
41 | #define DRV_NAME "ehea" | 41 | #define DRV_NAME "ehea" |
42 | #define DRV_VERSION "EHEA_0046" | 42 | #define DRV_VERSION "EHEA_0048" |
43 | 43 | ||
44 | #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \ | 44 | #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \ |
45 | | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) | 45 | | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) |
@@ -380,10 +380,11 @@ struct ehea_port_res { | |||
380 | }; | 380 | }; |
381 | 381 | ||
382 | 382 | ||
383 | #define EHEA_MAX_PORTS 16 | ||
383 | struct ehea_adapter { | 384 | struct ehea_adapter { |
384 | u64 handle; | 385 | u64 handle; |
385 | u8 num_ports; | 386 | struct ibmebus_dev *ebus_dev; |
386 | struct ehea_port *port[16]; | 387 | struct ehea_port *port[EHEA_MAX_PORTS]; |
387 | struct ehea_eq *neq; /* notification event queue */ | 388 | struct ehea_eq *neq; /* notification event queue */ |
388 | struct workqueue_struct *ehea_wq; | 389 | struct workqueue_struct *ehea_wq; |
389 | struct tasklet_struct neq_tasklet; | 390 | struct tasklet_struct neq_tasklet; |
@@ -406,7 +407,7 @@ struct ehea_port { | |||
406 | struct net_device *netdev; | 407 | struct net_device *netdev; |
407 | struct net_device_stats stats; | 408 | struct net_device_stats stats; |
408 | struct ehea_port_res port_res[EHEA_MAX_PORT_RES]; | 409 | struct ehea_port_res port_res[EHEA_MAX_PORT_RES]; |
409 | struct device_node *of_dev_node; /* Open Firmware Device Node */ | 410 | struct of_device ofdev; /* Open Firmware Device */ |
410 | struct ehea_mc_list *mc_list; /* Multicast MAC addresses */ | 411 | struct ehea_mc_list *mc_list; /* Multicast MAC addresses */ |
411 | struct vlan_group *vgrp; | 412 | struct vlan_group *vgrp; |
412 | struct ehea_eq *qp_eq; | 413 | struct ehea_eq *qp_eq; |
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 58364a0ff378..3527b391214d 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c | |||
@@ -580,7 +580,7 @@ static struct ehea_port *ehea_get_port(struct ehea_adapter *adapter, | |||
580 | { | 580 | { |
581 | int i; | 581 | int i; |
582 | 582 | ||
583 | for (i = 0; i < adapter->num_ports; i++) | 583 | for (i = 0; i < EHEA_MAX_PORTS; i++) |
584 | if (adapter->port[i]) | 584 | if (adapter->port[i]) |
585 | if (adapter->port[i]->logical_port_id == logical_port) | 585 | if (adapter->port[i]->logical_port_id == logical_port) |
586 | return adapter->port[i]; | 586 | return adapter->port[i]; |
@@ -2276,8 +2276,6 @@ static void ehea_tx_watchdog(struct net_device *dev) | |||
2276 | int ehea_sense_adapter_attr(struct ehea_adapter *adapter) | 2276 | int ehea_sense_adapter_attr(struct ehea_adapter *adapter) |
2277 | { | 2277 | { |
2278 | struct hcp_query_ehea *cb; | 2278 | struct hcp_query_ehea *cb; |
2279 | struct device_node *lhea_dn = NULL; | ||
2280 | struct device_node *eth_dn = NULL; | ||
2281 | u64 hret; | 2279 | u64 hret; |
2282 | int ret; | 2280 | int ret; |
2283 | 2281 | ||
@@ -2294,18 +2292,6 @@ int ehea_sense_adapter_attr(struct ehea_adapter *adapter) | |||
2294 | goto out_herr; | 2292 | goto out_herr; |
2295 | } | 2293 | } |
2296 | 2294 | ||
2297 | /* Determine the number of available logical ports | ||
2298 | * by counting the child nodes of the lhea OFDT entry | ||
2299 | */ | ||
2300 | adapter->num_ports = 0; | ||
2301 | lhea_dn = of_find_node_by_name(lhea_dn, "lhea"); | ||
2302 | do { | ||
2303 | eth_dn = of_get_next_child(lhea_dn, eth_dn); | ||
2304 | if (eth_dn) | ||
2305 | adapter->num_ports++; | ||
2306 | } while ( eth_dn ); | ||
2307 | of_node_put(lhea_dn); | ||
2308 | |||
2309 | adapter->max_mc_mac = cb->max_mc_mac - 1; | 2295 | adapter->max_mc_mac = cb->max_mc_mac - 1; |
2310 | ret = 0; | 2296 | ret = 0; |
2311 | 2297 | ||
@@ -2315,79 +2301,150 @@ out: | |||
2315 | return ret; | 2301 | return ret; |
2316 | } | 2302 | } |
2317 | 2303 | ||
2318 | static int ehea_setup_single_port(struct ehea_port *port, | 2304 | int ehea_get_jumboframe_status(struct ehea_port *port, int *jumbo) |
2319 | struct device_node *dn) | ||
2320 | { | 2305 | { |
2321 | int ret; | ||
2322 | u64 hret; | ||
2323 | struct net_device *dev = port->netdev; | ||
2324 | struct ehea_adapter *adapter = port->adapter; | ||
2325 | struct hcp_ehea_port_cb4 *cb4; | 2306 | struct hcp_ehea_port_cb4 *cb4; |
2326 | u32 *dn_log_port_id; | 2307 | u64 hret; |
2327 | int jumbo = 0; | 2308 | int ret = 0; |
2328 | |||
2329 | sema_init(&port->port_lock, 1); | ||
2330 | port->state = EHEA_PORT_DOWN; | ||
2331 | port->sig_comp_iv = sq_entries / 10; | ||
2332 | |||
2333 | if (!dn) { | ||
2334 | ehea_error("bad device node: dn=%p", dn); | ||
2335 | ret = -EINVAL; | ||
2336 | goto out; | ||
2337 | } | ||
2338 | |||
2339 | port->of_dev_node = dn; | ||
2340 | |||
2341 | /* Determine logical port id */ | ||
2342 | dn_log_port_id = (u32*)get_property(dn, "ibm,hea-port-no", NULL); | ||
2343 | |||
2344 | if (!dn_log_port_id) { | ||
2345 | ehea_error("bad device node: dn_log_port_id=%p", | ||
2346 | dn_log_port_id); | ||
2347 | ret = -EINVAL; | ||
2348 | goto out; | ||
2349 | } | ||
2350 | port->logical_port_id = *dn_log_port_id; | ||
2351 | |||
2352 | port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL); | ||
2353 | if (!port->mc_list) { | ||
2354 | ret = -ENOMEM; | ||
2355 | goto out; | ||
2356 | } | ||
2357 | |||
2358 | INIT_LIST_HEAD(&port->mc_list->list); | ||
2359 | 2309 | ||
2360 | ret = ehea_sense_port_attr(port); | 2310 | *jumbo = 0; |
2361 | if (ret) | ||
2362 | goto out; | ||
2363 | 2311 | ||
2364 | /* Enable Jumbo frames */ | 2312 | /* (Try to) enable *jumbo frames */ |
2365 | cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL); | 2313 | cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL); |
2366 | if (!cb4) { | 2314 | if (!cb4) { |
2367 | ehea_error("no mem for cb4"); | 2315 | ehea_error("no mem for cb4"); |
2316 | ret = -ENOMEM; | ||
2317 | goto out; | ||
2368 | } else { | 2318 | } else { |
2369 | hret = ehea_h_query_ehea_port(adapter->handle, | 2319 | hret = ehea_h_query_ehea_port(port->adapter->handle, |
2370 | port->logical_port_id, | 2320 | port->logical_port_id, |
2371 | H_PORT_CB4, | 2321 | H_PORT_CB4, |
2372 | H_PORT_CB4_JUMBO, cb4); | 2322 | H_PORT_CB4_JUMBO, cb4); |
2373 | |||
2374 | if (hret == H_SUCCESS) { | 2323 | if (hret == H_SUCCESS) { |
2375 | if (cb4->jumbo_frame) | 2324 | if (cb4->jumbo_frame) |
2376 | jumbo = 1; | 2325 | *jumbo = 1; |
2377 | else { | 2326 | else { |
2378 | cb4->jumbo_frame = 1; | 2327 | cb4->jumbo_frame = 1; |
2379 | hret = ehea_h_modify_ehea_port(adapter->handle, | 2328 | hret = ehea_h_modify_ehea_port(port->adapter-> |
2329 | handle, | ||
2380 | port-> | 2330 | port-> |
2381 | logical_port_id, | 2331 | logical_port_id, |
2382 | H_PORT_CB4, | 2332 | H_PORT_CB4, |
2383 | H_PORT_CB4_JUMBO, | 2333 | H_PORT_CB4_JUMBO, |
2384 | cb4); | 2334 | cb4); |
2385 | if (hret == H_SUCCESS) | 2335 | if (hret == H_SUCCESS) |
2386 | jumbo = 1; | 2336 | *jumbo = 1; |
2387 | } | 2337 | } |
2388 | } | 2338 | } else |
2339 | ret = -EINVAL; | ||
2340 | |||
2389 | kfree(cb4); | 2341 | kfree(cb4); |
2390 | } | 2342 | } |
2343 | out: | ||
2344 | return ret; | ||
2345 | } | ||
2346 | |||
2347 | static ssize_t ehea_show_port_id(struct device *dev, | ||
2348 | struct device_attribute *attr, char *buf) | ||
2349 | { | ||
2350 | struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev); | ||
2351 | return sprintf(buf, "0x%X", port->logical_port_id); | ||
2352 | } | ||
2353 | |||
2354 | static DEVICE_ATTR(log_port_id, S_IRUSR | S_IRGRP | S_IROTH, ehea_show_port_id, | ||
2355 | NULL); | ||
2356 | |||
2357 | static void __devinit logical_port_release(struct device *dev) | ||
2358 | { | ||
2359 | struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev); | ||
2360 | of_node_put(port->ofdev.node); | ||
2361 | } | ||
2362 | |||
2363 | static struct device *ehea_register_port(struct ehea_port *port, | ||
2364 | struct device_node *dn) | ||
2365 | { | ||
2366 | int ret; | ||
2367 | |||
2368 | port->ofdev.node = of_node_get(dn); | ||
2369 | port->ofdev.dev.parent = &port->adapter->ebus_dev->ofdev.dev; | ||
2370 | |||
2371 | sprintf(port->ofdev.dev.bus_id, "port%d", port->logical_port_id); | ||
2372 | port->ofdev.dev.release = logical_port_release; | ||
2373 | |||
2374 | ret = of_device_register(&port->ofdev); | ||
2375 | if (ret) { | ||
2376 | ehea_error("failed to register device. ret=%d", ret); | ||
2377 | goto out; | ||
2378 | } | ||
2379 | |||
2380 | ret = device_create_file(&port->ofdev.dev, &dev_attr_log_port_id); | ||
2381 | if (ret) { | ||
2382 | ehea_error("failed to register attributes, ret=%d", ret); | ||
2383 | goto out_unreg_of_dev; | ||
2384 | } | ||
2385 | |||
2386 | return &port->ofdev.dev; | ||
2387 | |||
2388 | out_unreg_of_dev: | ||
2389 | of_device_unregister(&port->ofdev); | ||
2390 | out: | ||
2391 | return NULL; | ||
2392 | } | ||
2393 | |||
2394 | static void ehea_unregister_port(struct ehea_port *port) | ||
2395 | { | ||
2396 | device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id); | ||
2397 | of_device_unregister(&port->ofdev); | ||
2398 | } | ||
2399 | |||
2400 | struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, | ||
2401 | u32 logical_port_id, | ||
2402 | struct device_node *dn) | ||
2403 | { | ||
2404 | int ret; | ||
2405 | struct net_device *dev; | ||
2406 | struct ehea_port *port; | ||
2407 | struct device *port_dev; | ||
2408 | int jumbo; | ||
2409 | |||
2410 | /* allocate memory for the port structures */ | ||
2411 | dev = alloc_etherdev(sizeof(struct ehea_port)); | ||
2412 | |||
2413 | if (!dev) { | ||
2414 | ehea_error("no mem for net_device"); | ||
2415 | ret = -ENOMEM; | ||
2416 | goto out_err; | ||
2417 | } | ||
2418 | |||
2419 | port = netdev_priv(dev); | ||
2420 | |||
2421 | sema_init(&port->port_lock, 1); | ||
2422 | port->state = EHEA_PORT_DOWN; | ||
2423 | port->sig_comp_iv = sq_entries / 10; | ||
2424 | |||
2425 | port->adapter = adapter; | ||
2426 | port->netdev = dev; | ||
2427 | port->logical_port_id = logical_port_id; | ||
2428 | |||
2429 | port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT); | ||
2430 | |||
2431 | port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL); | ||
2432 | if (!port->mc_list) { | ||
2433 | ret = -ENOMEM; | ||
2434 | goto out_free_ethdev; | ||
2435 | } | ||
2436 | |||
2437 | INIT_LIST_HEAD(&port->mc_list->list); | ||
2438 | |||
2439 | ret = ehea_sense_port_attr(port); | ||
2440 | if (ret) | ||
2441 | goto out_free_mc_list; | ||
2442 | |||
2443 | port_dev = ehea_register_port(port, dn); | ||
2444 | if (!port_dev) | ||
2445 | goto out_free_mc_list; | ||
2446 | |||
2447 | SET_NETDEV_DEV(dev, port_dev); | ||
2391 | 2448 | ||
2392 | /* initialize net_device structure */ | 2449 | /* initialize net_device structure */ |
2393 | SET_MODULE_OWNER(dev); | 2450 | SET_MODULE_OWNER(dev); |
@@ -2420,79 +2477,216 @@ static int ehea_setup_single_port(struct ehea_port *port, | |||
2420 | ret = register_netdev(dev); | 2477 | ret = register_netdev(dev); |
2421 | if (ret) { | 2478 | if (ret) { |
2422 | ehea_error("register_netdev failed. ret=%d", ret); | 2479 | ehea_error("register_netdev failed. ret=%d", ret); |
2423 | goto out_free; | 2480 | goto out_unreg_port; |
2424 | } | 2481 | } |
2425 | 2482 | ||
2483 | ret = ehea_get_jumboframe_status(port, &jumbo); | ||
2484 | if (ret) | ||
2485 | ehea_error("failed determining jumbo frame status for %s", | ||
2486 | port->netdev->name); | ||
2487 | |||
2426 | ehea_info("%s: Jumbo frames are %sabled", dev->name, | 2488 | ehea_info("%s: Jumbo frames are %sabled", dev->name, |
2427 | jumbo == 1 ? "en" : "dis"); | 2489 | jumbo == 1 ? "en" : "dis"); |
2428 | 2490 | ||
2429 | port->netdev = dev; | 2491 | return port; |
2430 | ret = 0; | ||
2431 | goto out; | ||
2432 | 2492 | ||
2433 | out_free: | 2493 | out_unreg_port: |
2494 | ehea_unregister_port(port); | ||
2495 | |||
2496 | out_free_mc_list: | ||
2434 | kfree(port->mc_list); | 2497 | kfree(port->mc_list); |
2435 | out: | 2498 | |
2436 | return ret; | 2499 | out_free_ethdev: |
2500 | free_netdev(dev); | ||
2501 | |||
2502 | out_err: | ||
2503 | ehea_error("setting up logical port with id=%d failed, ret=%d", | ||
2504 | logical_port_id, ret); | ||
2505 | return NULL; | ||
2506 | } | ||
2507 | |||
2508 | static void ehea_shutdown_single_port(struct ehea_port *port) | ||
2509 | { | ||
2510 | unregister_netdev(port->netdev); | ||
2511 | ehea_unregister_port(port); | ||
2512 | kfree(port->mc_list); | ||
2513 | free_netdev(port->netdev); | ||
2437 | } | 2514 | } |
2438 | 2515 | ||
2439 | static int ehea_setup_ports(struct ehea_adapter *adapter) | 2516 | static int ehea_setup_ports(struct ehea_adapter *adapter) |
2440 | { | 2517 | { |
2441 | int ret; | 2518 | struct device_node *lhea_dn; |
2519 | struct device_node *eth_dn = NULL; | ||
2520 | |||
2521 | u32 *dn_log_port_id; | ||
2442 | int port_setup_ok = 0; | 2522 | int port_setup_ok = 0; |
2443 | struct ehea_port *port; | 2523 | int i = 0; |
2444 | struct device_node *dn = NULL; | 2524 | |
2445 | struct net_device *dev; | 2525 | lhea_dn = adapter->ebus_dev->ofdev.node; |
2446 | int i; | 2526 | do { |
2527 | eth_dn = of_get_next_child(lhea_dn, eth_dn); | ||
2528 | if (!eth_dn) | ||
2529 | break; | ||
2447 | 2530 | ||
2448 | /* get port properties for all ports */ | 2531 | dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no", |
2449 | for (i = 0; i < adapter->num_ports; i++) { | 2532 | NULL); |
2533 | if (!dn_log_port_id) { | ||
2534 | ehea_error("bad device node: eth_dn name=%s", | ||
2535 | eth_dn->full_name); | ||
2536 | continue; | ||
2537 | } | ||
2450 | 2538 | ||
2539 | adapter->port[i] = ehea_setup_single_port(adapter, | ||
2540 | *dn_log_port_id, | ||
2541 | eth_dn); | ||
2451 | if (adapter->port[i]) | 2542 | if (adapter->port[i]) |
2452 | continue; /* port already up and running */ | 2543 | ehea_info("%s -> logical port id #%d", |
2544 | adapter->port[i]->netdev->name, | ||
2545 | *dn_log_port_id); | ||
2546 | i++; | ||
2547 | } while (eth_dn); | ||
2548 | |||
2549 | of_node_put(lhea_dn); | ||
2453 | 2550 | ||
2454 | /* allocate memory for the port structures */ | 2551 | /* Check for succesfully set up ports */ |
2455 | dev = alloc_etherdev(sizeof(struct ehea_port)); | 2552 | for (i = 0; i < EHEA_MAX_PORTS; i++) |
2553 | if (adapter->port[i]) | ||
2554 | port_setup_ok++; | ||
2456 | 2555 | ||
2457 | if (!dev) { | 2556 | if (port_setup_ok) |
2458 | ehea_error("no mem for net_device"); | 2557 | return 0; /* At least some ports are setup correctly */ |
2558 | |||
2559 | return -EINVAL; | ||
2560 | } | ||
2561 | |||
2562 | static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter, | ||
2563 | u32 logical_port_id) | ||
2564 | { | ||
2565 | struct device_node *lhea_dn; | ||
2566 | struct device_node *eth_dn = NULL; | ||
2567 | u32 *dn_log_port_id; | ||
2568 | |||
2569 | lhea_dn = adapter->ebus_dev->ofdev.node; | ||
2570 | do { | ||
2571 | eth_dn = of_get_next_child(lhea_dn, eth_dn); | ||
2572 | if (!eth_dn) | ||
2459 | break; | 2573 | break; |
2460 | } | ||
2461 | 2574 | ||
2462 | port = netdev_priv(dev); | 2575 | dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no", |
2463 | port->adapter = adapter; | 2576 | NULL); |
2464 | port->netdev = dev; | ||
2465 | adapter->port[i] = port; | ||
2466 | port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT); | ||
2467 | 2577 | ||
2468 | dn = of_find_node_by_name(dn, "ethernet"); | 2578 | if (dn_log_port_id) |
2469 | ret = ehea_setup_single_port(port, dn); | 2579 | if (*dn_log_port_id == logical_port_id) |
2470 | if (ret) { | 2580 | return eth_dn; |
2471 | /* Free mem for this port struct. The others will be | 2581 | |
2472 | processed on rollback */ | 2582 | } while (eth_dn); |
2473 | free_netdev(dev); | 2583 | |
2474 | adapter->port[i] = NULL; | 2584 | of_node_put(lhea_dn); |
2475 | ehea_error("eHEA port %d setup failed, ret=%d", i, ret); | 2585 | |
2476 | } | 2586 | return NULL; |
2587 | } | ||
2588 | |||
2589 | static ssize_t ehea_probe_port(struct device *dev, | ||
2590 | struct device_attribute *attr, | ||
2591 | const char *buf, size_t count) | ||
2592 | { | ||
2593 | struct ehea_adapter *adapter = dev->driver_data; | ||
2594 | struct ehea_port *port; | ||
2595 | struct device_node *eth_dn = NULL; | ||
2596 | int i; | ||
2597 | |||
2598 | u32 logical_port_id; | ||
2599 | |||
2600 | sscanf(buf, "%X", &logical_port_id); | ||
2601 | |||
2602 | port = ehea_get_port(adapter, logical_port_id); | ||
2603 | |||
2604 | if (port) { | ||
2605 | ehea_info("adding port with logical port id=%d failed. port " | ||
2606 | "already configured as %s.", logical_port_id, | ||
2607 | port->netdev->name); | ||
2608 | return -EINVAL; | ||
2477 | } | 2609 | } |
2610 | |||
2611 | eth_dn = ehea_get_eth_dn(adapter, logical_port_id); | ||
2478 | 2612 | ||
2479 | of_node_put(dn); | 2613 | if (!eth_dn) { |
2614 | ehea_info("no logical port with id %d found", logical_port_id); | ||
2615 | return -EINVAL; | ||
2616 | } | ||
2617 | |||
2618 | port = ehea_setup_single_port(adapter, logical_port_id, eth_dn); | ||
2480 | 2619 | ||
2481 | /* Check for succesfully set up ports */ | 2620 | if (port) { |
2482 | for (i = 0; i < adapter->num_ports; i++) | 2621 | for (i=0; i < EHEA_MAX_PORTS; i++) |
2483 | if (adapter->port[i]) | 2622 | if (!adapter->port[i]) { |
2484 | port_setup_ok++; | 2623 | adapter->port[i] = port; |
2624 | break; | ||
2625 | } | ||
2485 | 2626 | ||
2486 | if (port_setup_ok) | 2627 | ehea_info("added %s (logical port id=%d)", port->netdev->name, |
2487 | ret = 0; /* At least some ports are setup correctly */ | 2628 | logical_port_id); |
2488 | else | 2629 | } else |
2489 | ret = -EINVAL; | 2630 | return -EIO; |
2490 | 2631 | ||
2632 | return (ssize_t) count; | ||
2633 | } | ||
2634 | |||
2635 | static ssize_t ehea_remove_port(struct device *dev, | ||
2636 | struct device_attribute *attr, | ||
2637 | const char *buf, size_t count) | ||
2638 | { | ||
2639 | struct ehea_adapter *adapter = dev->driver_data; | ||
2640 | struct ehea_port *port; | ||
2641 | int i; | ||
2642 | u32 logical_port_id; | ||
2643 | |||
2644 | sscanf(buf, "%X", &logical_port_id); | ||
2645 | |||
2646 | port = ehea_get_port(adapter, logical_port_id); | ||
2647 | |||
2648 | if (port) { | ||
2649 | ehea_info("removed %s (logical port id=%d)", port->netdev->name, | ||
2650 | logical_port_id); | ||
2651 | |||
2652 | ehea_shutdown_single_port(port); | ||
2653 | |||
2654 | for (i=0; i < EHEA_MAX_PORTS; i++) | ||
2655 | if (adapter->port[i] == port) { | ||
2656 | adapter->port[i] = NULL; | ||
2657 | break; | ||
2658 | } | ||
2659 | } else { | ||
2660 | ehea_error("removing port with logical port id=%d failed. port " | ||
2661 | "not configured.", logical_port_id); | ||
2662 | return -EINVAL; | ||
2663 | } | ||
2664 | |||
2665 | return (ssize_t) count; | ||
2666 | } | ||
2667 | |||
2668 | static DEVICE_ATTR(probe_port, S_IWUSR, NULL, ehea_probe_port); | ||
2669 | static DEVICE_ATTR(remove_port, S_IWUSR, NULL, ehea_remove_port); | ||
2670 | |||
2671 | int ehea_create_device_sysfs(struct ibmebus_dev *dev) | ||
2672 | { | ||
2673 | int ret = device_create_file(&dev->ofdev.dev, &dev_attr_probe_port); | ||
2674 | if (ret) | ||
2675 | goto out; | ||
2676 | |||
2677 | ret = device_create_file(&dev->ofdev.dev, &dev_attr_remove_port); | ||
2678 | out: | ||
2491 | return ret; | 2679 | return ret; |
2492 | } | 2680 | } |
2493 | 2681 | ||
2494 | static int __devinit ehea_probe(struct ibmebus_dev *dev, | 2682 | void ehea_remove_device_sysfs(struct ibmebus_dev *dev) |
2495 | const struct of_device_id *id) | 2683 | { |
2684 | device_remove_file(&dev->ofdev.dev, &dev_attr_probe_port); | ||
2685 | device_remove_file(&dev->ofdev.dev, &dev_attr_remove_port); | ||
2686 | } | ||
2687 | |||
2688 | static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, | ||
2689 | const struct of_device_id *id) | ||
2496 | { | 2690 | { |
2497 | struct ehea_adapter *adapter; | 2691 | struct ehea_adapter *adapter; |
2498 | u64 *adapter_handle; | 2692 | u64 *adapter_handle; |
@@ -2505,6 +2699,8 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev, | |||
2505 | goto out; | 2699 | goto out; |
2506 | } | 2700 | } |
2507 | 2701 | ||
2702 | adapter->ebus_dev = dev; | ||
2703 | |||
2508 | adapter_handle = (u64*)get_property(dev->ofdev.node, "ibm,hea-handle", | 2704 | adapter_handle = (u64*)get_property(dev->ofdev.node, "ibm,hea-handle", |
2509 | NULL); | 2705 | NULL); |
2510 | if (adapter_handle) | 2706 | if (adapter_handle) |
@@ -2534,7 +2730,6 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev, | |||
2534 | dev_err(&dev->ofdev.dev, "sense_adapter_attr failed: %d", ret); | 2730 | dev_err(&dev->ofdev.dev, "sense_adapter_attr failed: %d", ret); |
2535 | goto out_free_res; | 2731 | goto out_free_res; |
2536 | } | 2732 | } |
2537 | dev_info(&dev->ofdev.dev, "%d eHEA ports found\n", adapter->num_ports); | ||
2538 | 2733 | ||
2539 | adapter->neq = ehea_create_eq(adapter, | 2734 | adapter->neq = ehea_create_eq(adapter, |
2540 | EHEA_NEQ, EHEA_MAX_ENTRIES_EQ, 1); | 2735 | EHEA_NEQ, EHEA_MAX_ENTRIES_EQ, 1); |
@@ -2558,15 +2753,21 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev, | |||
2558 | if (!adapter->ehea_wq) | 2753 | if (!adapter->ehea_wq) |
2559 | goto out_free_irq; | 2754 | goto out_free_irq; |
2560 | 2755 | ||
2756 | if (ehea_create_device_sysfs(dev)) | ||
2757 | goto out_kill_wq; | ||
2758 | |||
2561 | ret = ehea_setup_ports(adapter); | 2759 | ret = ehea_setup_ports(adapter); |
2562 | if (ret) { | 2760 | if (ret) { |
2563 | dev_err(&dev->ofdev.dev, "setup_ports failed"); | 2761 | dev_err(&dev->ofdev.dev, "setup_ports failed"); |
2564 | goto out_kill_wq; | 2762 | goto out_rem_dev_sysfs; |
2565 | } | 2763 | } |
2566 | 2764 | ||
2567 | ret = 0; | 2765 | ret = 0; |
2568 | goto out; | 2766 | goto out; |
2569 | 2767 | ||
2768 | out_rem_dev_sysfs: | ||
2769 | ehea_remove_device_sysfs(dev); | ||
2770 | |||
2570 | out_kill_wq: | 2771 | out_kill_wq: |
2571 | destroy_workqueue(adapter->ehea_wq); | 2772 | destroy_workqueue(adapter->ehea_wq); |
2572 | 2773 | ||
@@ -2585,24 +2786,20 @@ out: | |||
2585 | return ret; | 2786 | return ret; |
2586 | } | 2787 | } |
2587 | 2788 | ||
2588 | static void ehea_shutdown_single_port(struct ehea_port *port) | ||
2589 | { | ||
2590 | unregister_netdev(port->netdev); | ||
2591 | kfree(port->mc_list); | ||
2592 | free_netdev(port->netdev); | ||
2593 | } | ||
2594 | |||
2595 | static int __devexit ehea_remove(struct ibmebus_dev *dev) | 2789 | static int __devexit ehea_remove(struct ibmebus_dev *dev) |
2596 | { | 2790 | { |
2597 | struct ehea_adapter *adapter = dev->ofdev.dev.driver_data; | 2791 | struct ehea_adapter *adapter = dev->ofdev.dev.driver_data; |
2598 | u64 hret; | 2792 | u64 hret; |
2599 | int i; | 2793 | int i; |
2600 | 2794 | ||
2601 | for (i = 0; i < adapter->num_ports; i++) | 2795 | for (i = 0; i < EHEA_MAX_PORTS; i++) |
2602 | if (adapter->port[i]) { | 2796 | if (adapter->port[i]) { |
2603 | ehea_shutdown_single_port(adapter->port[i]); | 2797 | ehea_shutdown_single_port(adapter->port[i]); |
2604 | adapter->port[i] = NULL; | 2798 | adapter->port[i] = NULL; |
2605 | } | 2799 | } |
2800 | |||
2801 | ehea_remove_device_sysfs(dev); | ||
2802 | |||
2606 | destroy_workqueue(adapter->ehea_wq); | 2803 | destroy_workqueue(adapter->ehea_wq); |
2607 | 2804 | ||
2608 | ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter); | 2805 | ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter); |
@@ -2658,7 +2855,7 @@ static struct of_device_id ehea_device_table[] = { | |||
2658 | static struct ibmebus_driver ehea_driver = { | 2855 | static struct ibmebus_driver ehea_driver = { |
2659 | .name = "ehea", | 2856 | .name = "ehea", |
2660 | .id_table = ehea_device_table, | 2857 | .id_table = ehea_device_table, |
2661 | .probe = ehea_probe, | 2858 | .probe = ehea_probe_adapter, |
2662 | .remove = ehea_remove, | 2859 | .remove = ehea_remove, |
2663 | }; | 2860 | }; |
2664 | 2861 | ||