shill: reload_wifi: New PCI device helper script

This script is UDEV helper function that can help restart a PCI
based wireless LAN device.  It does so by removing the PCI device
from the bus, using the EC to cycle power on the device, then
performing a bus re-enumeration of the parent bus of the device.

BUG=chrome-os-partner:25275
TEST=Manual: Force restart by modifying the driver to output an event,
and ensure the device disappears and reappears as a new phy.

Change-Id: Ife0b05f8f545623d15d828610f180bb79669f926
Reviewed-on: https://chromium-review.googlesource.com/187474
Reviewed-by: mukesh agrawal <quiche@chromium.org>
Commit-Queue: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/bin/reload_wifi b/bin/reload_wifi
new file mode 100755
index 0000000..a069683
--- /dev/null
+++ b/bin/reload_wifi
@@ -0,0 +1,56 @@
+#!/bin/sh
+#
+# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# UDEV event helper script that restarts a hung WiFi device.
+
+POWER_DOWN_TIME_SECONDS=1
+DEVICE_REINITIALIZE_TIME_SECONDS=5
+
+set -e
+
+error () {
+  logger -t $0 "Error: $1"
+  exit 1
+}
+
+if [ "${SUBSYSTEM}" != "net" -o
+     "${DEVTYPE}" != "wlan" -o
+     "${EVENT}" != "device_hang" ] ; then
+  exit 0
+fi
+
+logger -t $0 "Restarting wireless lan network interface ${INTERFACE}"
+
+# The DEVPATH for a wlan network interface should look something like:
+#   /devices/pci0000:00/0000:00:1c.0/0000:01:00.0/net/wlan0
+if [ $(basename $(dirname "${DEVPATH}")) != 'net' ] ; then
+  error "Device path for ${INTERFACE} (${DEVPATH}) is invalid."
+fi
+
+device_path=$(dirname $(dirname "/sys${DEVPATH}"))
+device_remove_path="${device_path}/remove"
+bus_rescan_path=$(dirname "${device_path}")/rescan
+
+if [ ! -e "${device_remove_path}" ] ; then
+  error "Device remove path ${device_remove_path} does not exist"
+fi
+
+if [ ! -e "${bus_rescan_path}" ] ; then
+  error "Bus rescan path ${bus_rescan_path} does not exist"
+fi
+
+echo 1 > "${device_remove_path}"
+ectool wireless 0xe  # Disable wireless lan.
+ectool wireless 0x6  # Power down wireless lan.
+
+sleep ${POWER_DOWN_TIME_SECONDS}
+
+ectool wireless 0xe  # Power up wireless lan.
+ectool wireless 0xf  # Enable wireless lan.
+
+sleep ${DEVICE_REINITIALIZE_TIME_SECONDS}
+
+echo 1 > "${bus_rescan_path}"