If something is considered an input at a local scope, then you cannot assign it.
With digital logic there must be no more than one active driver on a net at any given time. When a signal is marked as an input, it means it's driver is external to the current scope. If the signal is an output, it means it's driver is internal to the currents scope (same level or sub-module). If the signal is an inout, then a protocol must exist to ensure only one drive is active at any given time.
There will be conflict if there is ever two or more active drivers with opposing values on the same net. In simulation this will result in X as the signal value. On FPGA/ASIC this will create a short between power and ground (which can damage the device).
You need to figure at what scope you need the an expression combining counter[10] and FIRE_IN. Create outputs to bring the value counter[10] up to that level. Create your intermediate logic at this level. Then connect this new logic to where FIRE_IN was used. This creates a feedback system.
Example:
module MODULENAME( output CNT10, /* ... */ );
/* ... */
assign CNT10 = counter[10];
/* ... */
endmodule
module TOPMODULE( /* ... */ );
/* ... */
assign some_logic = func(FIRE_IN, CNT10, /* ... */ );
MODULENAME instname( .CNT10_OUT(CNT10), .FIRE_IN(some_logic), /* ... */ );
/* ... */
endmodule
IMPORTANT: Keep your feedback synchronous (update on clock edge). Asynchronous feedback infer level-sensitive latches which are prone to timing issues that create glitches and unintended behavior. Keeping the feedback synchronous mitigates this risk.