From 038eab447d6fd693ea7d46c339de7d2ff28ed091 Mon Sep 17 00:00:00 2001 From: Weiguang Ruan Date: Thu, 31 Aug 2017 16:16:54 +0800 Subject: [PATCH] wifi: add pci reinit and remove_reinit function [4/7] PD#148564: add pci reinit and remove_reinit function pci_reinit: power on/off then rescan pci device. pci_remove_reinit: remove pci device first, then power on/off, rescan pci device. Change-Id: I03f3ceb7b526ce686b835eaacddbbd7f2ed2c384 Signed-off-by: Weiguang Ruan --- arch/arm64/boot/dts/amlogic/axg_s400.dts | 1 + arch/arm64/boot/dts/amlogic/axg_s400_v03.dts | 1 + drivers/amlogic/wifi/wifi_dt.c | 74 ++++++++++++++++++++++++++-- include/linux/amlogic/wifi_dt.h | 10 ++++ 4 files changed, 81 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/amlogic/axg_s400.dts b/arch/arm64/boot/dts/amlogic/axg_s400.dts index 708613b..af4ccef 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s400.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s400.dts @@ -574,6 +574,7 @@ interrupt_pin = <&gpio GPIOX_6 GPIO_ACTIVE_HIGH>; interrupts = < 0 67 4>; irq_trigger_type = "GPIO_IRQ_LOW"; + power_on_pin2 = <&gpio GPIOX_16 GPIO_ACTIVE_HIGH>; power_on_pin = <&gpio GPIOX_7 GPIO_ACTIVE_HIGH>; dhd_static_buf; //if use bcm wifi, config dhd_static_buf pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/amlogic/axg_s400_v03.dts b/arch/arm64/boot/dts/amlogic/axg_s400_v03.dts index 4a3fff1..803894e 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s400_v03.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s400_v03.dts @@ -574,6 +574,7 @@ interrupt_pin = <&gpio GPIOX_6 GPIO_ACTIVE_HIGH>; interrupts = < 0 67 4>; irq_trigger_type = "GPIO_IRQ_LOW"; + power_on_pin2 = <&gpio GPIOX_16 GPIO_ACTIVE_HIGH>; power_on_pin = <&gpio GPIOX_7 GPIO_ACTIVE_HIGH>; dhd_static_buf; //if use bcm wifi, config dhd_static_buf pinctrl-names = "default"; diff --git a/drivers/amlogic/wifi/wifi_dt.c b/drivers/amlogic/wifi/wifi_dt.c index a8923c7..aaadd9819b 100644 --- a/drivers/amlogic/wifi/wifi_dt.c +++ b/drivers/amlogic/wifi/wifi_dt.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include "../../gpio/gpiolib.h" #define OWNER_NAME "sdio_wifi" @@ -92,8 +93,8 @@ struct wifi_plat_info { #define USB_POWER_UP _IO('m', 1) #define USB_POWER_DOWN _IO('m', 2) -#define SDIO_POWER_UP _IO('m', 3) -#define SDIO_POWER_DOWN _IO('m', 4) +#define WIFI_POWER_UP _IO('m', 3) +#define WIFI_POWER_DOWN _IO('m', 4) #define SDIO_GET_DEV_TYPE _IO('m', 5) static struct wifi_plat_info wifi_info; static dev_t wifi_power_devno; @@ -242,6 +243,68 @@ static int wifi_power_release(struct inode *inode, struct file *file) { return 0; } + + +void pci_reinit(void) +{ + struct pci_bus *bus = NULL; + int cnt = 20; + + WIFI_INFO("pci wifi reinit!\n"); + + pci_lock_rescan_remove(); + while ((bus = pci_find_next_bus(bus)) != NULL) { + pci_rescan_bus(bus); + WIFI_INFO("rescanning pci device\n"); + cnt--; + if (cnt <= 0) + break; + } + pci_unlock_rescan_remove(); + +} +EXPORT_SYMBOL(pci_reinit); + +void pci_remove_reinit(unsigned int vid, unsigned int pid, unsigned int delBus) +{ + struct pci_bus *bus = NULL; + struct pci_dev *devDevice, *devBus; + int cnt = 20; + + WIFI_INFO("pci wifi remove and reinit\n"); + devDevice = pci_get_device(vid, pid, NULL); + + if (devDevice != NULL) { + WIFI_INFO("device 0x%x:0x%x found, remove it\n", vid, pid); + devBus = devDevice->bus->self; + pci_stop_and_remove_bus_device_locked(devDevice); + + if ((devBus > 0) && (devBus != NULL)) { + WIFI_INFO("remove ths bus this device on!\n"); + pci_stop_and_remove_bus_device_locked(devBus); + } + } else { + WIFI_INFO("target pci device not found 0x%x:0x%x\n", vid, pid); + } + + extern_wifi_set_enable(0); + msleep(200); + extern_wifi_set_enable(1); + msleep(200); + + pci_lock_rescan_remove(); + while ((bus = pci_find_next_bus(bus)) != NULL) { + pci_rescan_bus(bus); + WIFI_INFO("rescanning pci device\n"); + cnt--; + if (cnt <= 0) + break; + } + pci_unlock_rescan_remove(); + +} +EXPORT_SYMBOL(pci_remove_reinit); + static long wifi_power_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -255,17 +318,18 @@ static long wifi_power_ioctl(struct file *filp, break; case USB_POWER_DOWN: set_usb_wifi_power(0); - WIFI_INFO(KERN_INFO "Set usb_sdio wifi power down!\n"); + WIFI_INFO("Set usb_sdio wifi power down!\n"); break; - case SDIO_POWER_UP: + case WIFI_POWER_UP: extern_wifi_set_enable(0); mdelay(200); extern_wifi_set_enable(1); mdelay(200); sdio_reinit(); + pci_reinit(); WIFI_INFO("Set sdio wifi power up!\n"); break; - case SDIO_POWER_DOWN: + case WIFI_POWER_DOWN: extern_wifi_set_enable(0); break; case SDIO_GET_DEV_TYPE: diff --git a/include/linux/amlogic/wifi_dt.h b/include/linux/amlogic/wifi_dt.h index 43ee4ed..64cc1e3 100644 --- a/include/linux/amlogic/wifi_dt.h +++ b/include/linux/amlogic/wifi_dt.h @@ -20,7 +20,17 @@ extern void sdio_reinit(void); extern char *get_wifi_inf(void); + void extern_wifi_set_enable(int is_on); int wifi_irq_num(void); +/*amlogic 4.9 kernel support pci interface wifi*/ +extern void pci_lock_rescan_remove(void); +extern struct pci_bus *pci_find_next_bus(const struct pci_bus *from); +extern unsigned int pci_rescan_bus(struct pci_bus *bus); +extern void pci_unlock_rescan_remove(void); +extern struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, + struct pci_dev *from); +extern void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev); + #endif /* _wifi_dt_h_ */ -- 2.7.4