|
12 | 12 | #include <linux/interrupt.h> |
13 | 13 | #include <linux/bcma/bcma.h> |
14 | 14 | #include <linux/sched.h> |
| 15 | +#include <linux/sched/signal.h> |
| 16 | +#include <linux/kthread.h> |
15 | 17 | #include <linux/io.h> |
16 | 18 | #include <asm/unaligned.h> |
17 | 19 |
|
@@ -340,6 +342,11 @@ struct brcmf_pciedev_info { |
340 | 342 | u16 value); |
341 | 343 | struct brcmf_mp_device *settings; |
342 | 344 | struct brcmf_otp_params otp; |
| 345 | +#ifdef DEBUG |
| 346 | + u32 console_interval; |
| 347 | + bool console_active; |
| 348 | + struct timer_list timer; |
| 349 | +#endif |
343 | 350 | }; |
344 | 351 |
|
345 | 352 | struct brcmf_pcie_ringbuf { |
@@ -440,6 +447,9 @@ static void brcmf_pcie_setup(struct device *dev, int ret, |
440 | 447 | struct brcmf_fw_request *fwreq); |
441 | 448 | static struct brcmf_fw_request * |
442 | 449 | brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo); |
| 450 | +static void |
| 451 | +brcmf_pcie_fwcon_timer(struct brcmf_pciedev_info *devinfo, bool active); |
| 452 | +static void brcmf_pcie_debugfs_create(struct device *dev); |
443 | 453 |
|
444 | 454 | static u16 |
445 | 455 | brcmf_pcie_read_reg16(struct brcmf_pciedev_info *devinfo, u32 reg_offset) |
@@ -1413,6 +1423,11 @@ static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo) |
1413 | 1423 |
|
1414 | 1424 | static void brcmf_pcie_down(struct device *dev) |
1415 | 1425 | { |
| 1426 | + struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
| 1427 | + struct brcmf_pciedev *pcie_bus_dev = bus_if->bus_priv.pcie; |
| 1428 | + struct brcmf_pciedev_info *devinfo = pcie_bus_dev->devinfo; |
| 1429 | + |
| 1430 | + brcmf_pcie_fwcon_timer(devinfo, false); |
1416 | 1431 | } |
1417 | 1432 |
|
1418 | 1433 | static int brcmf_pcie_preinit(struct device *dev) |
@@ -1547,6 +1562,7 @@ static const struct brcmf_bus_ops brcmf_pcie_bus_ops = { |
1547 | 1562 | .get_memdump = brcmf_pcie_get_memdump, |
1548 | 1563 | .get_blob = brcmf_pcie_get_blob, |
1549 | 1564 | .reset = brcmf_pcie_reset, |
| 1565 | + .debugfs_create = brcmf_pcie_debugfs_create, |
1550 | 1566 | }; |
1551 | 1567 |
|
1552 | 1568 |
|
@@ -2123,6 +2139,8 @@ static void brcmf_pcie_setup(struct device *dev, int ret, |
2123 | 2139 |
|
2124 | 2140 | brcmf_pcie_bus_console_read(devinfo, false); |
2125 | 2141 |
|
| 2142 | + brcmf_pcie_fwcon_timer(devinfo, true); |
| 2143 | + |
2126 | 2144 | return; |
2127 | 2145 |
|
2128 | 2146 | fail: |
@@ -2197,6 +2215,105 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo) |
2197 | 2215 | return fwreq; |
2198 | 2216 | } |
2199 | 2217 |
|
| 2218 | +#ifdef DEBUG |
| 2219 | +static void |
| 2220 | +brcmf_pcie_fwcon_timer(struct brcmf_pciedev_info *devinfo, bool active) |
| 2221 | +{ |
| 2222 | + if (!active) { |
| 2223 | + if (devinfo->console_active) { |
| 2224 | + del_timer_sync(&devinfo->timer); |
| 2225 | + devinfo->console_active = false; |
| 2226 | + } |
| 2227 | + return; |
| 2228 | + } |
| 2229 | + |
| 2230 | + /* don't start the timer */ |
| 2231 | + if (devinfo->state != BRCMFMAC_PCIE_STATE_UP || |
| 2232 | + !devinfo->console_interval || !BRCMF_FWCON_ON()) |
| 2233 | + return; |
| 2234 | + |
| 2235 | + if (!devinfo->console_active) { |
| 2236 | + devinfo->timer.expires = jiffies + devinfo->console_interval; |
| 2237 | + add_timer(&devinfo->timer); |
| 2238 | + devinfo->console_active = true; |
| 2239 | + } else { |
| 2240 | + /* Reschedule the timer */ |
| 2241 | + mod_timer(&devinfo->timer, jiffies + devinfo->console_interval); |
| 2242 | + } |
| 2243 | +} |
| 2244 | + |
| 2245 | +static void |
| 2246 | +brcmf_pcie_fwcon(struct timer_list *t) |
| 2247 | +{ |
| 2248 | + struct brcmf_pciedev_info *devinfo = from_timer(devinfo, t, timer); |
| 2249 | + |
| 2250 | + if (!devinfo->console_active) |
| 2251 | + return; |
| 2252 | + |
| 2253 | + brcmf_pcie_bus_console_read(devinfo, false); |
| 2254 | + |
| 2255 | + /* Reschedule the timer if console interval is not zero */ |
| 2256 | + mod_timer(&devinfo->timer, jiffies + devinfo->console_interval); |
| 2257 | +} |
| 2258 | + |
| 2259 | +static int brcmf_pcie_console_interval_get(void *data, u64 *val) |
| 2260 | +{ |
| 2261 | + struct brcmf_pciedev_info *devinfo = data; |
| 2262 | + |
| 2263 | + *val = devinfo->console_interval; |
| 2264 | + |
| 2265 | + return 0; |
| 2266 | +} |
| 2267 | + |
| 2268 | +static int brcmf_pcie_console_interval_set(void *data, u64 val) |
| 2269 | +{ |
| 2270 | + struct brcmf_pciedev_info *devinfo = data; |
| 2271 | + |
| 2272 | + if (val > MAX_CONSOLE_INTERVAL) |
| 2273 | + return -EINVAL; |
| 2274 | + |
| 2275 | + devinfo->console_interval = val; |
| 2276 | + |
| 2277 | + if (!val && devinfo->console_active) |
| 2278 | + brcmf_pcie_fwcon_timer(devinfo, false); |
| 2279 | + else if (val) |
| 2280 | + brcmf_pcie_fwcon_timer(devinfo, true); |
| 2281 | + |
| 2282 | + return 0; |
| 2283 | +} |
| 2284 | + |
| 2285 | +DEFINE_SIMPLE_ATTRIBUTE(brcmf_pcie_console_interval_fops, |
| 2286 | + brcmf_pcie_console_interval_get, |
| 2287 | + brcmf_pcie_console_interval_set, |
| 2288 | + "%llu\n"); |
| 2289 | + |
| 2290 | +static void brcmf_pcie_debugfs_create(struct device *dev) |
| 2291 | +{ |
| 2292 | + struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
| 2293 | + struct brcmf_pub *drvr = bus_if->drvr; |
| 2294 | + struct brcmf_pciedev *pcie_bus_dev = bus_if->bus_priv.pcie; |
| 2295 | + struct brcmf_pciedev_info *devinfo = pcie_bus_dev->devinfo; |
| 2296 | + struct dentry *dentry = brcmf_debugfs_get_devdir(drvr); |
| 2297 | + |
| 2298 | + if (IS_ERR_OR_NULL(dentry)) |
| 2299 | + return; |
| 2300 | + |
| 2301 | + devinfo->console_interval = BRCMF_CONSOLE; |
| 2302 | + |
| 2303 | + debugfs_create_file("console_interval", 0644, dentry, devinfo, |
| 2304 | + &brcmf_pcie_console_interval_fops); |
| 2305 | +} |
| 2306 | + |
| 2307 | +#else |
| 2308 | +void brcmf_pcie_fwcon_timer(struct brcmf_pciedev_info *devinfo, bool active) |
| 2309 | +{ |
| 2310 | +} |
| 2311 | + |
| 2312 | +static void brcmf_pcie_debugfs_create(struct device *dev) |
| 2313 | +{ |
| 2314 | +} |
| 2315 | +#endif |
| 2316 | + |
2200 | 2317 | static int |
2201 | 2318 | brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
2202 | 2319 | { |
@@ -2278,6 +2395,11 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
2278 | 2395 | goto fail_brcmf; |
2279 | 2396 | } |
2280 | 2397 |
|
| 2398 | +#ifdef DEBUG |
| 2399 | + /* Set up the fwcon timer */ |
| 2400 | + timer_setup(&devinfo->timer, brcmf_pcie_fwcon, 0); |
| 2401 | +#endif |
| 2402 | + |
2281 | 2403 | fwreq = brcmf_pcie_prepare_fw_request(devinfo); |
2282 | 2404 | if (!fwreq) { |
2283 | 2405 | ret = -ENOMEM; |
@@ -2323,6 +2445,7 @@ brcmf_pcie_remove(struct pci_dev *pdev) |
2323 | 2445 |
|
2324 | 2446 | devinfo = bus->bus_priv.pcie->devinfo; |
2325 | 2447 | brcmf_pcie_bus_console_read(devinfo, false); |
| 2448 | + brcmf_pcie_fwcon_timer(devinfo, false); |
2326 | 2449 |
|
2327 | 2450 | devinfo->state = BRCMFMAC_PCIE_STATE_DOWN; |
2328 | 2451 | if (devinfo->ci) |
@@ -2366,6 +2489,7 @@ static int brcmf_pcie_pm_enter_D3(struct device *dev) |
2366 | 2489 | bus = dev_get_drvdata(dev); |
2367 | 2490 | devinfo = bus->bus_priv.pcie->devinfo; |
2368 | 2491 |
|
| 2492 | + brcmf_pcie_fwcon_timer(devinfo, false); |
2369 | 2493 | brcmf_bus_change_state(bus, BRCMF_BUS_DOWN); |
2370 | 2494 |
|
2371 | 2495 | devinfo->mbdata_completed = false; |
@@ -2409,6 +2533,7 @@ static int brcmf_pcie_pm_leave_D3(struct device *dev) |
2409 | 2533 | brcmf_bus_change_state(bus, BRCMF_BUS_UP); |
2410 | 2534 | brcmf_pcie_intr_enable(devinfo); |
2411 | 2535 | brcmf_pcie_hostready(devinfo); |
| 2536 | + brcmf_pcie_fwcon_timer(devinfo, true); |
2412 | 2537 | return 0; |
2413 | 2538 | } |
2414 | 2539 |
|
|
0 commit comments