Skip to content

Commit

Permalink
wimax/i2400m: introduce i2400m->bus_setup/release
Browse files Browse the repository at this point in the history
The SDIO subdriver of the i2400m requires certain steps to be done
before we do any acces to the device, even for doing firmware upload.

This lead to a few ugly hacks, which basically involve doing those
steps in probe() before calling i2400m_setup() and undoing them in
disconnect() after claling i2400m_release(); but then, much of those
steps have to be repeated when resetting the device, suspending, etc
(in upcoming pre/post reset support).

Thus, a new pair of optional, bus-specific calls
i2400m->bus_{setup/release} are introduced. These are used to setup
basic infrastructure needed to load firmware onto the device.

This commit also updates the SDIO subdriver to use said calls.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
  • Loading branch information
Inaky Perez-Gonzalez committed Oct 19, 2009
1 parent c2315b4 commit 0856ccf
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 38 deletions.
20 changes: 18 additions & 2 deletions drivers/net/wimax/i2400m/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,24 +41,26 @@
* __i2400m_dev_start()
*
* i2400m_setup()
* i2400m->bus_setup()
* i2400m_bootrom_init()
* register_netdev()
* wimax_dev_add()
* i2400m_dev_start()
* __i2400m_dev_start()
* i2400m_dev_bootstrap()
* i2400m_tx_setup()
* i2400m->bus_dev_start()
* i2400m_firmware_check()
* i2400m_check_mac_addr()
* wimax_dev_add()
*
* i2400m_release()
* wimax_dev_rm()
* i2400m_dev_stop()
* __i2400m_dev_stop()
* i2400m_dev_shutdown()
* i2400m->bus_dev_stop()
* i2400m_tx_release()
* i2400m->bus_release()
* wimax_dev_rm()
* unregister_netdev()
*/
#include "i2400m.h"
Expand Down Expand Up @@ -784,6 +786,15 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
snprintf(wimax_dev->name, sizeof(wimax_dev->name),
"i2400m-%s:%s", dev->bus->name, dev_name(dev));

if (i2400m->bus_setup) {
result = i2400m->bus_setup(i2400m);
if (result < 0) {
dev_err(dev, "bus-specific setup failed: %d\n",
result);
goto error_bus_setup;
}
}

result = i2400m_bootrom_init(i2400m, bm_flags);
if (result < 0) {
dev_err(dev, "read mac addr: bootrom init "
Expand Down Expand Up @@ -846,6 +857,9 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
unregister_pm_notifier(&i2400m->pm_notifier);
error_read_mac_addr:
error_bootrom_init:
if (i2400m->bus_release)
i2400m->bus_release(i2400m);
error_bus_setup:
d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
return result;
}
Expand All @@ -872,6 +886,8 @@ void i2400m_release(struct i2400m *i2400m)
wimax_dev_rm(&i2400m->wimax_dev);
unregister_netdev(i2400m->wimax_dev.net_dev);
unregister_pm_notifier(&i2400m->pm_notifier);
if (i2400m->bus_release)
i2400m->bus_release(i2400m);
i2400m_bm_buf_free(i2400m);
d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
}
Expand Down
27 changes: 27 additions & 0 deletions drivers/net/wimax/i2400m/i2400m.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
*
* bus_probe()
* i2400m_setup()
* i2400m->bus_setup()
* boot rom initialization / read mac addr
* network / WiMAX stacks registration
* i2400m_dev_start()
Expand All @@ -137,6 +138,7 @@
* i2400m_dev_shutdown()
* i2400m->bus_dev_stop()
* network / WiMAX stack unregistration
* i2400m->bus_release()
*
* At this point, control and data communications are possible.
*
Expand Down Expand Up @@ -214,12 +216,35 @@ struct i2400m_barker_db;
* Members marked with [fill] must be filled out/initialized before
* calling i2400m_setup().
*
* Note the @bus_setup/@bus_release, @bus_dev_start/@bus_dev_release
* call pairs are very much doing almost the same, and depending on
* the underlying bus, some stuff has to be put in one or the
* other. The idea of setup/release is that they setup the minimal
* amount needed for loading firmware, where us dev_start/stop setup
* the rest needed to do full data/control traffic.
*
* @bus_tx_block_size: [fill] SDIO imposes a 256 block size, USB 16,
* so we have a tx_blk_size variable that the bus layer sets to
* tell the engine how much of that we need.
*
* @bus_pl_size_max: [fill] Maximum payload size.
*
* @bus_setup: [optional fill] Function called by the bus-generic code
* [i2400m_setup()] to setup the basic bus-specific communications
* to the the device needed to load firmware. See LIFE CYCLE above.
*
* NOTE: Doesn't need to upload the firmware, as that is taken
* care of by the bus-generic code.
*
* @bus_release: [optional fill] Function called by the bus-generic
* code [i2400m_release()] to shutdown the basic bus-specific
* communications to the the device needed to load firmware. See
* LIFE CYCLE above.
*
* This function does not need to reset the device, just tear down
* all the host resources created to handle communication with
* the device.
*
* @bus_dev_start: [fill] Function called by the bus-generic code
* [i2400m_dev_start()] to setup the bus-specific communications
* to the the device. See LIFE CYCLE above.
Expand Down Expand Up @@ -490,8 +515,10 @@ struct i2400m {
size_t bus_pl_size_max;
unsigned bus_bm_retries;

int (*bus_setup)(struct i2400m *);
int (*bus_dev_start)(struct i2400m *);
void (*bus_dev_stop)(struct i2400m *);
void (*bus_release)(struct i2400m *);
void (*bus_tx_kick)(struct i2400m *);
int (*bus_reset)(struct i2400m *, enum i2400m_reset_type);
ssize_t (*bus_bm_cmd_send)(struct i2400m *,
Expand Down
100 changes: 64 additions & 36 deletions drivers/net/wimax/i2400m/sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,66 @@ int i2400ms_enable_function(struct sdio_func *func, unsigned maxtries)
}


/*
* Setup minimal device communication infrastructure needed to at
* least be able to update the firmware.
*/
static
int i2400ms_bus_setup(struct i2400m *i2400m)
{
int result;
struct i2400ms *i2400ms =
container_of(i2400m, struct i2400ms, i2400m);
struct device *dev = i2400m_dev(i2400m);
struct sdio_func *func = i2400ms->func;

sdio_claim_host(func);
result = sdio_set_block_size(func, I2400MS_BLK_SIZE);
sdio_release_host(func);
if (result < 0) {
dev_err(dev, "Failed to set block size: %d\n", result);
goto error_set_blk_size;
}

result = i2400ms_enable_function(func, 1);
if (result < 0) {
dev_err(dev, "Cannot enable SDIO function: %d\n", result);
goto error_func_enable;
}

result = i2400ms_rx_setup(i2400ms);
if (result < 0)
goto error_rx_setup;
return 0;

error_rx_setup:
sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
error_func_enable:
error_set_blk_size:
return result;
}


/*
* Tear down minimal device communication infrastructure needed to at
* least be able to update the firmware.
*/
static
void i2400ms_bus_release(struct i2400m *i2400m)
{
struct i2400ms *i2400ms =
container_of(i2400m, struct i2400ms, i2400m);
struct sdio_func *func = i2400ms->func;

i2400ms_rx_release(i2400ms);
sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
}


/*
* Setup driver resources needed to communicate with the device
*
Expand Down Expand Up @@ -315,17 +375,12 @@ int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt)
if (i2400m->wimax_dev.net_dev->reg_state == NETREG_REGISTERED)
netif_tx_disable(i2400m->wimax_dev.net_dev);

i2400ms_rx_release(i2400ms);
sdio_claim_host(i2400ms->func);
sdio_disable_func(i2400ms->func);
sdio_release_host(i2400ms->func);
i2400ms_bus_release(i2400m);

/* Wait for the device to settle */
msleep(40);

result = i2400ms_enable_function(i2400ms->func, 0);
if (result >= 0)
i2400ms_rx_setup(i2400ms);
result = i2400ms_bus_setup(i2400m);
} else
BUG();
if (result < 0 && rt != I2400M_RT_BUS) {
Expand Down Expand Up @@ -449,8 +504,10 @@ int i2400ms_probe(struct sdio_func *func,

i2400m->bus_tx_block_size = I2400MS_BLK_SIZE;
i2400m->bus_pl_size_max = I2400MS_PL_SIZE_MAX;
i2400m->bus_setup = i2400ms_bus_setup;
i2400m->bus_dev_start = i2400ms_bus_dev_start;
i2400m->bus_dev_stop = i2400ms_bus_dev_stop;
i2400m->bus_release = i2400ms_bus_release;
i2400m->bus_tx_kick = i2400ms_bus_tx_kick;
i2400m->bus_reset = i2400ms_bus_reset;
/* The iwmc3200-wimax sometimes requires the driver to try
Expand All @@ -462,20 +519,6 @@ int i2400ms_probe(struct sdio_func *func,
i2400m->bus_bm_mac_addr_impaired = 1;
i2400m->bus_bm_pokes_table = &i2400ms_pokes[0];

sdio_claim_host(func);
result = sdio_set_block_size(func, I2400MS_BLK_SIZE);
sdio_release_host(func);
if (result < 0) {
dev_err(dev, "Failed to set block size: %d\n", result);
goto error_set_blk_size;
}

result = i2400ms_enable_function(i2400ms->func, 1);
if (result < 0) {
dev_err(dev, "Cannot enable SDIO function: %d\n", result);
goto error_func_enable;
}

/*
* Before we are enabling the device interrupt register, make
* sure the buffer used during bootmode operation is setup so
Expand All @@ -488,10 +531,6 @@ int i2400ms_probe(struct sdio_func *func,
goto error_bootmode_buf_setup;
}

result = i2400ms_rx_setup(i2400ms);
if (result < 0)
goto error_rx_setup;

result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT);
if (result < 0) {
dev_err(dev, "cannot setup device: %d\n", result);
Expand All @@ -509,15 +548,8 @@ int i2400ms_probe(struct sdio_func *func,
error_debugfs_add:
i2400m_release(i2400m);
error_setup:
i2400ms_rx_release(i2400ms);
error_rx_setup:
i2400m_bm_buf_free(i2400m);
error_bootmode_buf_setup:
sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
error_func_enable:
error_set_blk_size:
sdio_set_drvdata(func, NULL);
free_netdev(net_dev);
error_alloc_netdev:
Expand All @@ -535,12 +567,8 @@ void i2400ms_remove(struct sdio_func *func)

d_fnstart(3, dev, "SDIO func %p\n", func);
debugfs_remove_recursive(i2400ms->debugfs_dentry);
i2400ms_rx_release(i2400ms);
i2400m_release(i2400m);
sdio_set_drvdata(func, NULL);
sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
free_netdev(net_dev);
d_fnend(3, dev, "SDIO func %p\n", func);
}
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wimax/i2400m/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -416,8 +416,10 @@ int i2400mu_probe(struct usb_interface *iface,

i2400m->bus_tx_block_size = I2400MU_BLK_SIZE;
i2400m->bus_pl_size_max = I2400MU_PL_SIZE_MAX;
i2400m->bus_setup = NULL;
i2400m->bus_dev_start = i2400mu_bus_dev_start;
i2400m->bus_dev_stop = i2400mu_bus_dev_stop;
i2400m->bus_release = NULL;
i2400m->bus_tx_kick = i2400mu_bus_tx_kick;
i2400m->bus_reset = i2400mu_bus_reset;
i2400m->bus_bm_retries = I2400M_USB_BOOT_RETRIES;
Expand Down

0 comments on commit 0856ccf

Please sign in to comment.